【问题标题】:C - Mixed Qsort with Struct (String and Double)C - 带结构的混合 Qsort(字符串和双精度)
【发布时间】:2019-04-25 03:51:23
【问题描述】:

我有一个几乎完整的代码,需要对一些东西进行 Qsort,首先我有整数数组,浮点数数组,然后我有 char 和 double 组合数组的结构。需要以某种方式对它们进行 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 时,它会按价格对产品下的 PRICES 数组进行排序,如果用户选择 4,它应该按名称排序,在这两种情况下它都应该输出价格和名称,只是不同按它的排序。

【问题讨论】:

  • qsort(prices, ..., sizeof(double) 是错误的,ComparFuncStructNameComparFuncStructPrice 都需要转换为结构指针。您需要将结构的大小传递给函数。避免此类错误的一个好方法是写qsort(array, num, sizeof *array, comparefn),类似于int *x = malloc(n * sizeof *x)
  • Need help using qsort with an array of structs 的可能重复项。下次你也可以使用搜索框:stackoverflow.com/search?q=qsort+struct
  • 第一步:更改sizeof(array) / sizeof(type); --> sizeof array / sizeof array[0];

标签: c arrays loops struct qsort


【解决方案1】:

在比较函数中,指针(在您的情况下为xy)是指向数组元素的指针。如果数组是int,那么它是一个指向int(即int *)的指针。如果它是一个结构数组,那么它们是指向 结构 的指针(例如 product *)。

要访问结构的成员,您当然需要使用正确的指向结构的访问,例如箭头运算符-&gt;

如果您将指针保存在适当的变量中也会更容易,这样您就不必一直进行所有的转换。事实上,如果您想将传递的数据用作指针而不是值,则根本不需要强制转换,因为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

【讨论】:

  • 所以你不必一直做所有的演员。”对,但是为什么演员:const product *a = (const product *) x;
  • @alk 在我展示的示例中可能差别不大,但在数值比较函数中差别更大。而且你不能真正取消演员表,但你不需要一直这样做。
  • 我的意思是为什么不只是const product *a = x;
  • 为了完整起见,可能会提到OP的原始比较函数如CompareFuncInt不应该抛弃const限定符。
  • @gsamaras 这个答案中有足够的信息,可以让 OP 修复价格比较功能而不会被灌输。
【解决方案2】:

改变这个:

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

到:

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

因为结构数组只有一种大小,无论您是想按名称还是价格排序。此外,无论您想按名称还是价格排序,数组中每个元素的大小都等于结构的大小。

与按名称排序时类似。


另外,您的比较功能是错误的。首先,您需要将每个 void 指针转换为一个结构。然后,你需要使用结构体的相关字段来进行比较。

对于价格比较,使用 less and 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

【讨论】:

  • return (pa-&gt;price - pb-&gt;price); 返回从 double 转换而来的 int。在价格超过INT_MAX 的不太可能的情况下,或者价格在 0 和 1 之间的可能性更大的情况下,这将不起作用。一个很好的使用技巧是 return ((pa-&gt;price &gt; pb-&gt;price) - (pa-&gt;price &lt; pb-&gt;price));,它将返回 -1、0 或 1。
  • 它不起作用@IanAbbott,这就是我改变它的原因(很可能是在你写评论的时候)! :)
猜你喜欢
  • 2015-02-12
  • 1970-01-01
  • 1970-01-01
  • 2014-01-01
  • 2011-08-11
  • 2013-10-10
  • 2015-04-10
  • 1970-01-01
  • 2011-05-13
相关资源
最近更新 更多