C - Смешанный Qsort со структурой (String и Double) - PullRequest
0 голосов
/ 22 ноября 2018

У меня есть почти полный код, мне нужно Qsort некоторые вещи, сначала у меня есть массив целых чисел, массив с плавающей точкой, а затем у меня есть структура с char и двойной комбинированный массив.Нужно как-то qsort их, но я застрял.

Вот мой код, у меня нет проблем с сортировкой целых чисел и чисел, но я не могу завершить сортировку структуры.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define LEN 20

typedef struct product
{
    double price;
    char name[LEN];
} product;


int ComparFuncInt(const void *x, const void *y);
int ConparFuncFloat(const void *x, const void *y);
int ComparFuncStructName(const void *x, const void *y);
int ComparFuncStructPrice(const void *x, const void *y);
/* void PrintIntegerArray(int *numbers, int len);
void PrintFloatArray(float *numbers, int len);
void PrintStructArray(product *items, int len);
*/
int main(void)
{
    unsigned option;

    /* initialized variables to be used with functions */
    int numArr1[] = {15, 25, 3, 19, 22, 17, -54, 0, 9};
    float numArr2[] = {76.40f, 11.2f, 235.4f, 76.50f, 341.6f};
    product prices[] = {{0.75f, "Milk"}, {0.99f, "Yogurt"}, {3.19f, "Cucumber"},
                        {1.09f, "Orange"}, {0.80f, "Bread"}, {0.99f, "Juice"}};
    int numCount = sizeof(numArr1) / sizeof(int);
    float floatCount = sizeof(numArr2) / sizeof(float);
    double doubleCount = sizeof(struct product) / sizeof(double);
    char charCount = sizeof(struct product) / sizeof(char);


    while (1)
    {
        printf("\n\nSelect your action!\n\n");
        printf("1. Sort integers (numArr1)\n");
        printf("2. Sort decimals (numArr2)\n");
        printf("3. Sort structures by price\n");
        printf("4. Sort structures by name\n");
        printf("0. Exit\n");
        scanf("%u", &option);
        switch (option)
        {
            case 1:
                qsort(numArr1, (size_t)numCount, sizeof(int), ComparFuncInt);
                for (int i = 0; i < numCount; printf("%3d", numArr1[i]), i++);
                break;
            case 2:
                qsort(numArr2, (size_t)floatCount, sizeof(float), ConparFuncFloat);
                for (int j = 0; j < floatCount; printf("%.2f ", numArr2[j]), j++);
                break;
            case 3:
                qsort(prices, (size_t)doubleCount, sizeof(double), ComparFuncStructPrice);
                for (int k = 0; k < doubleCount; printf("%.2f ", prices[k].price), k++);
                break;
            case 4:
                qsort(prices, (size_t)charCount, sizeof(char), ComparFuncStructName);
                for (int l = 0; l < charCount; printf("%s", prices[l].name), l++);
                break;
            case 0:
                exit(1);
                break;
            default:
                printf("Only selections from 1 to 4 and 0 are accepted\n");
        }
    }
    return EXIT_SUCCESS;
}


int ComparFuncInt(const void *x, const void *y){
    if(* (int*)x > *(int*)y) return 1;
    else if(* (int*)x < *(int*)y) return -1;
    else return 0;
}
int ConparFuncFloat(const void *x, const void *y){
    if(* (float *)x > *(float *)y) return 1;
    else if(* (float *)x < *(float *)y) return -1;
    else return 0;
}
int ComparFuncStructName(const void *x, const void *y){
    const char *pa = *(const char**)x;
    const char *pb = *(const char**)y;
    return strcmp(pa,pb);
}
int ComparFuncStructPrice(const void *x, const void *y){
    if(* (float *)x > *(float *)y) return 1;
    else if(* (float *)x < *(float *)y) return -1;
    else return 0;
}

Я хочу сделать это, так как когда пользователь выбирает 3, он идет и сортирует массив ЦЕН по категориям товаров, а если пользователь выбирает 4, он должен сортировать по именам, в обоих случаях он должен выводить как цену, так и имя, только разница вчто это было отсортировано.

Ответы [ 2 ]

0 голосов
/ 22 ноября 2018

Измените это:

qsort(prices, (size_t)doubleCount, sizeof(double), ComparFuncStructPrice);        

на:

qsort(prices, 6, sizeof(prices[0]), ComparFuncStructPrice);

, поскольку массив структур имеет один размер, независимо от того, хотите ли вы отсортировать по имени или цене.Более того, размер каждого элемента массива равен размеру структуры, независимо от того, хотите ли вы отсортировать по имени или цене.

Аналогично для сортировки по именам.


Кроме того, ваши функции сравнения неверны.Во-первых, вам нужно скрыть каждый указатель void на структуру.Затем для сравнения необходимо использовать соответствующее поле структуры.

Для сравнения цен используйте операторы less и more.Если вы просто вычтете, вы получите неправильные результаты.


Собрав все вместе (и отбросив неструктурные массивы), вы получите:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define LEN 20

typedef struct product
{
    double price;
    char name[LEN];
} product;


int ComparFuncStructName(const void *x, const void *y);
int ComparFuncStructPrice(const void *x, const void *y);
/* 
void PrintStructArray(product *items, int len);
*/
int main(void)
{
    unsigned option;
    product prices[] = {{0.75f, "Milk"}, {0.99f, "Yogurt"}, {3.19f, "Cucumber"},
                        {1.09f, "Orange"}, {0.80f, "Bread"}, {0.99f, "Juice"}};
    size_t pricesCount = sizeof prices / sizeof prices[0];
    while (1)
    {
        printf("\n\nSelect your action!\n\n");
        printf("3. Sort structures by price\n");
        printf("4. Sort structures by name\n");
        printf("0. Exit\n");
        scanf("%u", &option);
        switch (option)
        {
            case 3:
                qsort(prices, pricesCount, sizeof(prices[0]), ComparFuncStructPrice);
                for (size_t k = 0; k < pricesCount; printf("%f ", prices[k].price), k++);
                break;
            case 4:
                qsort(prices, pricesCount, sizeof(prices[0]), ComparFuncStructName);
                for (size_t l = 0; l < pricesCount; printf("%s ", prices[l].name), l++);
                break;
            case 0:
                exit(1);
                break;
            default:
                printf("Only selections from 1 to 4 and 0 are accepted\n");
        }
    }
    return EXIT_SUCCESS;
}

int ComparFuncStructName(const void *x, const void *y){
    const product* pa = (const product*) x;
    const product* pb = (const product*) y;
    return strcmp(pa->name, pb->name);
}
int ComparFuncStructPrice(const void *x, const void *y){
    const product* pa = (const product*) x;
    const product* pb = (const product*) y;
    return (pa->price > pb->price) - (pa->price < pb->price);
}

Вывод (если я выберу)сортировать по имени):

Select your action!

3. Sort structures by price
4. Sort structures by name
0. Exit
Bread Cucumber Juice Milk Orange Yogurt 

Select your action!

3. Sort structures by price
4. Sort structures by name
0. Exit
0 голосов
/ 22 ноября 2018

В функциях сравнения указатели (x и y в вашем случае) являются указателями на элементы массива.Если массив является int, то это указатель на int (то есть int *).Если это массив структур, то они являются указателями на структуру (например, product *).

Чтобы получить доступ к членам структуры, вам, конечно, необходимо использовать правильный указательдоступ к структуре, как, например, оператор стрелки ->.

Также проще, если вы сохраняете указатели в правильных переменных, поэтому вам не нужно все время выполнять приведение.Фактически, если вы хотите использовать переданные данные в качестве указателей, а не значений, преобразовывать их вообще не нужно, поскольку void * неявно преобразуется практически в любой другой тип указателя (кроме указателей на функции).

Таким образом, для функции сравнения структуры вы можете выполнить, например,

int ComparFuncStructName(const void *x, const void *y){
    const product *a = x;
    const product *b = y;

    return strcmp(a->name, b->name);
}

Или, конечно, поскольку вы сортируете массив структуры, размер элемента массива равен размеру структуры, поэтому вам нужноисправьте это тоже:

qsort(prices, charCount, sizeof prices[0], ComparFuncStructName);

О, и вы подсчитываете количество элементов в структуре, а также неверны.Формула sizeof array / sizeof array[0]. Всегда .Независимо от типа массива или его элементов.Результат sizeof равен всегда size_t, поэтому вы должны использовать его как тип для всех операций sizeof.

Так что вам нужно сделать

size_t charCount = sizeof prices / sizeof prices[0];

На несвязанной и более стилистической ноте: не объединяйте вызов printf с выражением приращения цикла for.Это сделает код более трудным для чтения, понимания, отслеживания и (самое главное) сопровождения.

Вместо этого поместите все операторы в тело цикла:

for (int l = 0; l < charCount; l++)
    printf("%s", prices[l].name);

Вы также этого не делаетенужны разные итерационные переменные для циклов.Они будут локальными для цикла внутри их собственной области видимости, поэтому вы можете повторно использовать i для всех циклов.

...