关于数组:C-带结构的混合Qsort(字符串和双精度)

C - Mixed Qsort with Struct (String and Double)

我有一个几乎完整的代码,需要Qsort一些东西,首先我有一个整数数组,一个浮点数组,然后我有一个带有char和double组合数组的struct。需要以某种方式对它们进行排序,但是我被卡住了。

这是我的代码,对整数和浮点数排序没有问题,但是我无法完成结构排序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#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("\
\
Select your action!\
\
"
);
        printf("1. Sort integers (numArr1)\
"
);
        printf("2. Sort decimals (numArr2)\
"
);
        printf("3. Sort structures by price\
"
);
        printf("4. Sort structures by name\
"
);
        printf("0. Exit\
"
);
        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\
"
);
        }
    }
    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,则应按名称进行排序,在两种情况下都应同时输出价格和名称,只是区别在于按其排序方式。


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

要访问结构的成员,您当然需要使用适当的指向结构的指针访问,例如箭头运算符->

如果将指针保存在适当的变量中也很容易,这样您就不必一直进行所有转换。实际上,如果要使用传递的数据作为指针而不是值,则根本不需要强制转换,因为void *可以隐式转换为几乎任何其他指针类型(函数指针除外)。

因此对于您的结构比较功能,您可以执行例如

1
2
3
4
5
6
int ComparFuncStructName(const void *x, const void *y){
    const product *a = x;
    const product *b = y;

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

或者,当然,由于您要对结构数组进行排序,因此数组的元素大小就是结构的大小,因此您也需要修复该问题:

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

哦,您计算结构中元素的数量也是错误的。公式为sizeof array / sizeof array[0]。总是。无论数组的类型或其元素如何。 sizeof的结果始终为size_t,因此您也应将其用作所有sizeof操作的类型。

所以你需要做

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

在不相关且更具风格上的注意事项:请勿将printf调用与for循环的增量表达式结合使用。这将使代码更难于阅读,理解,遵循和(最重要的是)维护。

将所有语句放在循环体中:

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

您也不需要为循环使用不同的迭代变量。它们对于它们自己范围内的循环而言是本地的,因此您可以为所有循环重用i


更改此内容:

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

至:

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

因为结构数组只有一个大小,所以无论您要按名称还是按价格排序。而且,无论您要按名称还是按价格排序,数组每个元素的大小都等于该结构的大小。

类似于按名称排序的方式。

此外,您的比较功能是错误的。首先,您需要隐瞒指向结构的所有void指针。然后,您需要使用结构的相关字段进行比较。

为进行价格比较,请使用越来越少的运算符。如果简单地减去,将会得到错误的结果。

将所有内容放在一起(并丢弃非结构数组),您将得到:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#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("\
\
Select your action!\
\
"
);
        printf("3. Sort structures by price\
"
);
        printf("4. Sort structures by name\
"
);
        printf("0. Exit\
"
);
        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\
"
);
        }
    }
    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);
}

输出(如果我选择按名称排序):

1
2
3
4
5
6
7
8
9
10
11
12
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