Сортировка списка по всем полям в любых направлениях. Использовать указатели на функции - 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;
}

Объяснение кода листинга программы

В данном коде реализована сортировка списка продуктов по всем полям в любых направлениях.

  1. Список функций:
    • product_list_alloc() - выделяет память под список продуктов
    • product_list_free() - освобождает память под списком продуктов
    • product_list_imput() - считывает данные о продуктах в список
    • product_list_print() - выводит данные о продуктах из списка
    • swap() - меняет местами два указателя на память
    • sort() - сортирует список по заданному полю с использованием алгоритма быстрой сортировки
    • quicksort() - сортирует список по заданному полю с использованием алгоритма быстрой сортировки
    • name_cmp() - сравнивает продукты по полю название в порядке возрастания
    • name_rcmp() - сравнивает продукты по полю название в порядке убывания
    • quantity_cmp() - сравнивает продукты по полю количество в порядке возрастания
    • quantity_rcmp() - сравнивает продукты по полю количество в порядке убывания
  2. Описание основной функции:
    • main() - считывает количество списков продуктов, считывает данные о продуктах, сортирует список по выбранному полю и выводит отсортированный список на экран.
  3. Описание переменных:
    • count - количество списков продуктов
    • products - список продуктов
    • ncmp - номер поля для сортировки
    • cmps - указатели на функции сравнения продуктов по полям
  4. Объяснение работы кода:
    • С помощью функции product_list_alloc() выделяется память под список продуктов.
    • В цикле с помощью функции product_list_imput() считываются данные о продуктах в список.
    • С помощью функции product_list_print() выводятся данные о продуктах из списка.
    • Выбирается поле для сортировки с помощью переменной ncmp.
    • С помощью функции quicksort() сортируется список продуктов по выбранному полю.
    • С помощью функции product_list_print() выводится отсортированный список на экран.
    • С помощью функции product_list_free() освобождается память под списком продуктов. Таким образом, данный код реализует сортировку списка продуктов по всем полям в любых направлениях.

Оцени полезность:

13   голосов , оценка 3.923 из 5
Похожие ответы