qsort() 不对结构中的数据进行排序

qsort() doesn't sort data from structure

我有一个结构:

typedef struct personalData
{
    char name[20];
    char * remarks;
    int age;
    float weight;
} personalData;

我需要使用 qsort() 按权重对数据进行排序。这是我的 weightSort 函数:

void weightSort(personalData * data[], int len)
{
    qsort(data, len, sizeof(struct personalData *), structSortWeight);
}

其中len = 10(在使用一些不同的函数之前计算的,但可能无关紧要),data[]定义在main():

struct personalData * data[10];

最后是 structSortWeight:

int structSortWeight(const void *a, const void *b)
{
    personalData *p1 = (personalData *)a;
    personalData *p2 = (personalData *)b;

    return (p1->weight - p2->weight);
}

我的程序在开始排序时崩溃了。我想补充一点,当我将 qsort() 中的第三个参数更改为 sizeof(float) 时,它不会崩溃,但 p1->weightp2->weight 指向一些垃圾。

main()中的调用函数:

weightSort(data, len);

personalData * data[] 已经分配了一些数据。

qsort 比较函数的签名是

int (*comp)(const void *, const void *) 

返回 float 根本不起作用。

这个数组声明:

struct personalData * data[10];

没有声明适合用作第一个参数的对象

void weightSort(personalData data[], int len)

变量和函数参数具有不同级别的间接寻址。您的实际数据是 指向 struct personalData 的指针数组,而函数参数适用于结构本身的数组。这会产生未定义的行为。因此,您传递给 qsort() 的项目大小可能在功能上更相关,因此不正确:使用 main() 中声明的数据,您想要的项目大小不是 struct personalData 的大小,而是指向一个指针的大小 (sizeof(struct personalData *)).

另外,你的比较函数是错误的。首先,它必须 return 一个 int,而不是 float,但其次,由于您正在排序的元素是指向结构的指针,因此呈现给比较的参数函数将是指向此类指针的指针。您将它们视为直接指向结构的指针。

您的比较函数接收指向列表中两个元素的指针,每个元素也是一个指针。所以每个参数的真实类型是 personalData **,但你将它们转换为 personalData *。所以您将指针视为结构实例,这就是您看到垃圾的原因。

您需要在比较函数中添加额外的间接级别:

int structSortWeight(const void *a, const void *b)
{
    // no need to cast from void *
    const personalData **p1 = a;
    const personalData **p2 = b;

    return ((*p1)->weight - (*p2)->weight);
}

return (p1->weight - p2->weight); 不是合适的比较。这将减去 2 float 个值并转换为 int。比较函数必须return合理一致的结果。

考虑权重 A、B、C:1.1、2.0、2.9。

比较 f(A,B) returns int 0.
比较 f(B,C) returns int 0.
比较 f(A,C) returns int 1. // 如果 A==B 和 B==C

,这没有意义

这种不一致会欺骗 qsort(),导致 未定义的行为 (UB)。

更好的比较功能

int structSortWeight2(const void *a, const void *b) {
    const personalData **p1 = (const personalData **)a;
    const personalData **p2 = (const personalData **)b;
    // 2 compares are done, each returning an `int`
    return ((*p1)->weight > (*p2)->weight) - ((*p1)->weight < (*p2)->weight);
}

代码还有

中详述的其他问题