【问题标题】:qsort() doesn't sort data from structureqsort() 不对结构中的数据进行排序
【发布时间】:2018-06-12 11:38:47
【问题描述】:

我有一个结构:

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[] 已经分配了一些数据。

【问题讨论】:

  • 如果问题是您目前所提供的片段所暗示的问题,那么您需要注意编译器的警告,如果您没有收到任何警告,请打开它们.
  • struct personalData * data[10]; 作为weightSort 的第一个参数是不合法的。类型不兼容。你是怎么做到的?你的调用代码是什么样的?
  • 目前我没有收到任何错误,因为我已经更改了一些内容,这要归功于答案,并且程序没有崩溃,但指针仍然指向一些垃圾。我马上改一下代码。

标签: c struct qsort


【解决方案1】:

qsort比较函数的签名是

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

返回 float 根本不起作用。

【讨论】:

  • 我改变了它,但它并没有解决问题。不过谢谢你的建议。
【解决方案2】:

这个数组声明:

struct personalData * data[10];

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

void weightSort(personalData data[], int len)

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

此外,您的比较功能是错误的。首先,它必须返回一个int,而不是float,但其次,由于您要排序的元素是指向结构的指针,所以提供给比较函数的参数将是指向此类指针的指针。您将它们视为直接指向结构的指针。

【讨论】:

  • 感谢您的回答。我认为该声明不适合这些对象。但是,我得到了它并且应该使用该声明,但在我看来这是一个错误。我已经在我的代码中更改了您的建议,但 p1->weight 和 p2->weight 仍然没有任何意义。结果, qsort() 不对数据进行排序。我已将这些更改放在问题的代码中。
  • @botq,您没有解决我在回答中指出的关键问题之一:“由于您要排序的元素是指向结构的指针,因此提供给比较函数的参数将指向这样的指针。您将它们视为直接指向结构的指针。”因此,当然 p1->weightp2->weight 没有指向任何合理的东西。无论您如何转换它们,这些指针都指向其他指针,而不是 personalData 类型的对象。
【解决方案3】:

您的比较函数接收指向列表中两个元素的指针,每个元素也是一个指针。所以每个参数的真实类型是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);
}

【讨论】:

  • 就是这样!非常感谢。
【解决方案4】:

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

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

比较 f(A,B) 返回 int 0。
比较 f(B,C) 返回 int 0。
比较 f(A,C) 返回 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);
}

代码有其他问题,详见@John Bollinger

【讨论】:

  • 非常有用的建议。这解决了我的下一个问题,因为一些接近的权重没有按 qsort() 排序。谢谢。
猜你喜欢
  • 1970-01-01
  • 2014-05-21
  • 2021-05-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-16
  • 2021-12-15
相关资源
最近更新 更多