Сортировка списка по всем полям в любых направлениях. Использовать указатели на функции - C (СИ)
Формулировка задачи:
В общем, я запутался.
Вот задание.
Необходимо разработать программу согласно варианту
задания. При реализации использовать указатели на
функции и (или) массивы указателей на функции.
--------------------------------------------------
Дан список записей типа ТОВАР
(размер списка и его элементы вводятся пользователем).
Упорядочить список по любому из полей в любом направлении.
Поле и направление выбирает пользователь. В функцию сортировки
должен передаваться указатель на функцию сравнения двух элементов. (20 баллов).
ТОВАР:
- наименование товара (строка 15 символов);
- единицы измерения (строка 5 символов);
- цена (вещественное число с двумя знаками после запятой);
- количество (целое положительное число).
То, что накалякано
На эти строки на намекать. Исправил
Сейчас попробую со строками также провернуть
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
typedef struct
{
char name[16];
char mesr[6];
double price;
int count;
}Good;
typedef Good *Ptr;
typedef int (*Pfun)( void *, void * );
int cmpNM ( void *, void * );
int cmpCNT( void *, void * );
void sortbychoice( Ptr , int, size_t, void (*), Pfun );
void swap ( Ptr , Ptr );
int main( int argc, char *argv[ ] )
{
//printf( "%d", offsetof( Good, count) );
int d = 0, count;
printf( "Enter count of lists: ");
while( !d || count <= 0)
{
d = scanf( "%d", &count );
if( !d || count <= 0 ) { while( getchar( ) != '\n' ); printf( "Repeat: "); }
}
fflush( stdin );
int i;
Ptr list = (Good*)calloc( count, sizeof(Good));
for( i = 0; i < count; i++ ) { printf( "Name|Measure|Price|Count: " ); scanf( "%s%s%lf%d", list[i].name, list[i].mesr, &list[i].price, &list[i].count ); while( getchar( ) != '\n' );}
//
//sortbychoice( list, count, sizeof(char)*15, list[i].name, cmpNM );
sortbychoice( list, count, offsetof( Good, count ), &list[i].count, cmpCNT);
for( i = 0; i < count; i ++ ) printf( "Name: %s | Measure: %s | Price: %3.2lf | Count: %03d\n", list[i].name, list[i].mesr, list[i].price, list[i].count );
system( "pause" );
getch( );
return 0;
}
void swap ( Ptr arg1, Ptr arg2 )
{
Good temp = *arg1;
*arg1 = *arg2;
*arg2 = temp;
return;
}
int cmpNM( void * arg1, void * arg2 )
{
if( strcmp( (char*)arg1, (char*)arg2 ) == 1 ) return 1;
else return 0;
}
int cmpCNT( void * arg1, void *arg2 )
{
if(*((int*)arg1) > *((int*)arg2)) return 1;
else return 0;
}
void sortbychoice ( Ptr good, int count, size_t size, void *arr, Pfun fun )
{
Ptr mass = good;
int i, j, im;
char * ar = ( char* )arr;
for( i = 0; i < count - 1; i++ ){
im = i;
for( j = i + 1; j < count; j++ ) if( fun( (void*)( ar + im*size), (void*)( ar + j * size )) ) im = j;
swap( &mass[i], &mass[im] );
}
return;
}
дело в том, что я не могу понять, как мне обращаться к началу памяти одного и того же поля в массиве структур. Делал такое с обычными массивами, вроде всё работало. Вот как делал:
void SortArray( void *array, unsigned num, size_t size, int (*fun)(void *arg1, void *arg2), void (*fun1)( void *arg1, void *arg2))
{
int i, j;
int imin, imax;
char *ptr = (char* )array; // указатель на начало памяти массива
for( i = 0; i < num - 1; i += 2 )
{
imin = i;
for( j = i + 2; j < num; j += 2 )
if( fun( (void*)(ptr + imin*size), (void*)(ptr + j*size)) > 0 ) imin = j;
fun1( ptr + i*size, ptr + imin*size);// смещение указателя на size бацтов массив
}
for( i = 1; i < num - 1; i += 2 )
{
imax = i;
for( j = i + 2; j < num; j += 2 )
if( fun( (void*)(ptr + imax*size), (void*)(ptr + j*size)) < 0 ) imax = j;
fun1( ptr + i*size, ptr + imax*size );// смещение указателя на size бацтов массив
}
}
//sortbychoice( list, count, sizeof(char)*15, list[i].name, cmpNM );
* * sortbychoice( list, count, offsetof( Good, count ), &list[i].count, cmpCNT);
В общем, для сортровки по кол - ву работает вроде.
void sortbychoice ( Ptr good, int count, void *arr, Pfun fun )
{
Ptr mass = good;
int i, j, im;
char * ar = ( char * )arr; // указатель на начало памяти выбранного поля аргумента arg
for( i = 0; i < count - 1; i++ ){
im = i;
for( j = i + 1; j < count; j++ ) if( fun( (void*)( ar + im*sizeof( Good)), (void*)( ar + j * sizeof(Good) )) ) im = j;
swap( &mass[i], &mass[im] );
}
return;
}
В общем, пока работает. Если найдёте грабли ещё, укажите, пожалуйста.
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
typedef struct
{
char name[16];
char mesr[6];
double price;
int count;
}Good;
typedef Good *Ptr;
typedef int (*Pfun)( void *, void * );
int cmpNM ( void *, void * );
int cmpCNT( void *, void * );
void sortbychoice( Ptr , int, void (*), Pfun ); // для 1 - ого аргумента необходимо передать 2 - ой указатель
void swap ( Ptr , Ptr );
int main( int argc, char *argv[ ] )
{
//printf( "%d", offsetof( Good, count) );
int d = 0, count;
printf( "Enter count of lists: ");
while( !d || count <= 0)
{
d = scanf( "%d", &count );
if( !d || count <= 0 ) { while( getchar( ) != '\n' ); printf( "Repeat: "); }
}
fflush( stdin );
int i;
Ptr list = (Good*)calloc( count, sizeof(Good));
for( i = 0; i < count; i++ ) { printf( "Name|Measure|Price|Count: " ); scanf( "%s%s%lf%d", list[i].name, list[i].mesr, &list[i].price, &list[i].count ); while( getchar( ) != '\n' );}
//
sortbychoice( list, count,list[0].name, cmpNM );
//sortbychoice( list, count, &list[0].count, cmpCNT);
for( i = 0; i < count; i ++ ) printf( "Name: %s | Measure: %s | Price: %3.2lf | Count: %03d\n", list[i].name, list[i].mesr, list[i].price, list[i].count );
system( "pause" );
getch( );
return 0;
}
void swap ( Ptr arg1, Ptr arg2 )
{
Good temp = *arg1;
*arg1 = *arg2;
*arg2 = temp;
return;
}
int cmpNM( void * arg1, void * arg2 )
{
if( strcmp( (char*)arg1, (char*)arg2 ) == 1 ) return 1;
else return 0;
}
int cmpCNT( void * arg1, void *arg2 )
{
if(*((int*)arg1) > *((int*)arg2)) return 1;
else return 0;
}
void sortbychoice ( Ptr good, int count, void *arr, Pfun fun )
{
Ptr mass = good;
int i, j, im;
char * ar = ( char * )arr;
for( i = 0; i < count - 1; i++ ){
im = i;
for( j = i + 1; j < count; j++ ) if( fun( (void*)( ar + im*sizeof( Good)), (void*)( ar + j * sizeof(Good) )) ) im = j;
swap( &mass[i], &mass[im] );
}
return;
}Решение задачи: «Сортировка списка по всем полям в любых направлениях. Использовать указатели на функции»
textual
Листинг программы
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXNAME 16
#define MAXUNIT 6
typedef int (*Pf)(void*, void*);
typedef struct {
char name[MAXNAME];
char unit[MAXUNIT];
double price;
int quantity;
} Product;
Product *product_list_alloc(int count)
{
Product * list = malloc(count * sizeof(*list));
return list;
}
void product_list_free(Product *list)
{
free(list);
}
void product_list_imput(Product *list, int count)
{
for (size_t i=0; i<count; i++)
{
printf("Name|Measure|Price|Count: ");
scanf("%s %s %lf %d", list[i].name, list[i].unit,
&list[i].price, &list[i].quantity);
}
}
void product_list_print(Product *list, int count)
{
for (size_t i=0; i<count; i++)
{
printf( "Name: %s | Measure: %s | Price: %3.2lf | Count: %3d\n",
list[i].name, list[i].unit, list[i].price, list[i].quantity );
}
}
static void swap(void *x, void *y, size_t l) {
char *a = x, *b = y, c;
while(l--) {
c = *a;
*a++ = *b;
*b++ = c;
}
}
static void sort(char *array, size_t size, int (*cmp)(void*,void*), int begin, int end) {
if (end > begin) {
void *pivot = array + begin;
int l = begin + size;
int r = end;
while(l < r) {
if (cmp(array+l,pivot) <= 0) {
l += size;
} else if ( cmp(array+r, pivot) > 0 ) {
r -= size;
} else if ( l < r ) {
swap(array+l, array+r, size);
}
}
l -= size;
swap(array+begin, array+l, size);
sort(array, size, cmp, begin, l);
sort(array, size, cmp, r, end);
}
}
void quicksort (void *array, size_t nitems, size_t size, int (*cmp)(void*,void*)) {
sort(array, size, cmp, 0, nitems*size);
}
int name_cmp(void *a, void *b)
{
Product *p1 = a;
Product *p2 = b;
return strcmp(p1->name, p2->name);
}
int name_rcmp(void *a, void *b)
{
Product *p1 = a;
Product *p2 = b;
return strcmp(p2->name, p1->name);
}
int quantity_cmp(void *a, void *b)
{
Product *p1 = a;
Product *p2 = b;
return (p1->quantity - p2->quantity);
}
int quantity_rcmp(void *a, void *b)
{
Product *p1 = a;
Product *p2 = b;
return (p2->quantity - p1->quantity);
}
int main(void)
{
int count;
Pf cmps[4] = {name_cmp, name_rcmp, quantity_cmp, quantity_rcmp};
printf("Enter count of lists: ");
scanf("%d", &count);
Product *products = product_list_alloc(count);
product_list_imput(products, count);
product_list_print(products, count);
int ncmp = 3;
quicksort(products, count, sizeof(*products), cmps[ncmp]);
product_list_print(products, count);
product_list_free(products);
return 0;
}
Объяснение кода листинга программы
В данном коде реализована сортировка списка продуктов по всем полям в любых направлениях.
- Список функций:
product_list_alloc()- выделяет память под список продуктовproduct_list_free()- освобождает память под списком продуктовproduct_list_imput()- считывает данные о продуктах в списокproduct_list_print()- выводит данные о продуктах из спискаswap()- меняет местами два указателя на памятьsort()- сортирует список по заданному полю с использованием алгоритма быстрой сортировкиquicksort()- сортирует список по заданному полю с использованием алгоритма быстрой сортировкиname_cmp()- сравнивает продукты по полюназваниев порядке возрастанияname_rcmp()- сравнивает продукты по полюназваниев порядке убыванияquantity_cmp()- сравнивает продукты по полюколичествов порядке возрастанияquantity_rcmp()- сравнивает продукты по полюколичествов порядке убывания
- Описание основной функции:
main()- считывает количество списков продуктов, считывает данные о продуктах, сортирует список по выбранному полю и выводит отсортированный список на экран.
- Описание переменных:
count- количество списков продуктовproducts- список продуктовncmp- номер поля для сортировкиcmps- указатели на функции сравнения продуктов по полям
- Объяснение работы кода:
- С помощью функции
product_list_alloc()выделяется память под список продуктов. - В цикле с помощью функции
product_list_imput()считываются данные о продуктах в список. - С помощью функции
product_list_print()выводятся данные о продуктах из списка. - Выбирается поле для сортировки с помощью переменной
ncmp. - С помощью функции
quicksort()сортируется список продуктов по выбранному полю. - С помощью функции
product_list_print()выводится отсортированный список на экран. - С помощью функции
product_list_free()освобождается память под списком продуктов. Таким образом, данный код реализует сортировку списка продуктов по всем полям в любых направлениях.
- С помощью функции