为什么 qsort 在对结构数组进行排序时不起作用

Why qsort doesn't work, while sorting an array of structures

我有一个这样的结构数组

typedef union value_
    {
        double d;
        int i;
    } value;

typedef struct number_
{
    char type;
    value val;
}number;

type 可以是 'i''d',具体取决于联合字段中存储的整数或双精度值。 该数组如下所示:

Integer value: -3
Double value: 4.84
Integer value: -4
Double value: 1.65
Integer value: 1
Double value: 2.54
Integer value: 2
Double value: -0.09

最主要的是整数和双精度数是一个接一个的。我需要按以下方式使用 qsort 对这个数组进行排序:整数应该从低到高排序,反之亦然。 我用下面的函数来比较:

int compare(const void *A, const void *B){

    number *a = (number*)A;
    number *b = (number*)B;
    
    if (a->type == b->type) {
        if (a->type =='i') {
            return a->val.i - b->val.i;
        } else {
            if (a->val.d > b->val.d) return -1;
            if (a->val.d < b->val.d) return 1;
            else return 0;
        }
    } else {
        return 0;
    }
}

假设,如果联合中的值有不同的类型,那么returns 0 没有比较,所以这样的序列,如int,double,int,double应该被保存。但结果如下:

Integer value: -1
Integer value: -5
Double value: 0.20
Integer value: 2
Double value: -0.04
Double value: -2.69
Integer value: 4
Integer value: 5
Double value: 2.04
Integer value: 3

如果在那种情况下应该 return 0,为什么它会用整数更改双精度数?

如果您需要保留原始列表的 intdouble 类型的 'interlocked pattern',但对每组 intdouble 值进行排序,那么您不能在完整列表中按原样使用标准 qsort 函数

但是,您可以做的是将 intdouble 条目分离到新列表中,分别对它们进行排序,然后将两个排序后的列表合并回原始列表,取 intdouble 来自相关排序列表的条目,具体取决于原始列表中条目的类型。

这是一种可能的实现方式(使用代码中的 compare 函数,保持不变——尽管如果您制作两个特定于类型的比较函数以用于分离的列表,则大型列表的性能会更好):

void printlist(number* list, size_t n)
{
    for (size_t i = 0; i < n; ++i) {
        if (list[i].type == 'i') printf("%d ", list[i].val.i);
        else printf("%lf ", list[i].val.d);
    }
    printf("\n");
}

int main()
{
    number list[] = {
        { 'i', { .i = -3} },   { 'd', { .d = 1.65} },
        { 'i', { .i = -4} },   { 'd', { .d = 4.85} },
        { 'i', { .i =  1} },   { 'd', { .d = -.09} },
        { 'i', { .i =  2} },   { 'd', { .d = 2.54} },
    };
    size_t Tcount = sizeof(list) / sizeof(*list), Icount = 0, Dcount = 0; // Counts for total, ints and doubles
    for (size_t i = 0; i < Tcount; ++i) {
        if (list[i].type == 'i') ++Icount;
        else ++Dcount;
    }
    // Display original list ...
    printlist(list, Tcount);
    number* Ilist = malloc(sizeof(number) * Icount);
    number* Dlist = malloc(sizeof(number) * Dcount);
    size_t Iindex = 0, Dindex = 0;
    // Separate lists ...
    for (size_t i = 0; i < Tcount; ++i) {
        if (list[i].type == 'i') Ilist[Iindex++] = list[i];
        else Dlist[Dindex++] = list[i];
    }
    // Sort each list separately ...
    qsort(Ilist, Icount, sizeof(number), compare);
    qsort(Dlist, Dcount, sizeof(number), compare);
    // Merge sorted lists ...
    Iindex = 0, Dindex = 0;
    for (size_t i = 0; i < Tcount; ++i) {
        if (list[i].type == 'i') list[i] = Ilist[Iindex++];
        else list[i] = Dlist[Dindex++];
    }
    // Display sorted list ...
    printlist(list, 8);
    // Clean up ...
    free(Ilist);
    free(Dlist);
    return 0;
}