【问题标题】:How to sort an array of structs that has some NULL values using qsort如何使用 qsort 对具有一些 NULL 值的结构数组进行排序
【发布时间】:2026-01-07 10:00:01
【问题描述】:

我有一个结构数组,需要根据属性进行排序。我做了一个比较函数来做到这一点,但问题是数组可以有 NULL 值,这会导致错误。以下是我的代码的相关部分:

#define MAX_NUM 5
struct d {
    int id;
    int p;
    int prio;
} d;
struct d *P[MAX_NUM];


int compare(const void *p, const void *q)
{
    int l = ((struct d *)p)->prio;
    int r = ((struct d *)q)->prio;
    if (l < r) return -1;
    else if (l > r) return 1;
    else  return 0;

}

我这样调用 qsort 函数:

qsort(P, MAX_NUM, sizeof(P[0]), compare);

我认为这在正常情况下应该可以工作,但由于数组 P 有 NULL 值,所以它没有。我怎样才能使这项工作?

编辑:我最后一次修改基于 cmets 的比较函数:

int usporedba(const void* a, const void* b) 
{
   struct d arg1 = *(const struct d*)a;
   struct d arg2 = *(const struct d*)b;

   if (arg1.prio < arg2.prio) return -1;
   if (arg1.prio > arg2.prio) return 1;
   return 0;

}

【问题讨论】:

  • struct d *P[MAX_NUM]; 这是一个指向结构体的数组,而问题是结构体数组struct dretva 未定义。 sizeof(d)这不是P中元素的大小,请贴出真实代码。
  • 我的问题标题有误,我对 C 不是很有经验。我在这里更改了一些变量名,但我想我忘记了一些,但现在已经修复了。整个代码有点长,所以我只发布了重要部分,其他一切都与问题无关。
  • 问题仍然是您想要排序的内容。结构数组将是struct d P[MAX_NUM];。相反,发布的代码显示了一个指向结构的指针数组。任何一个都可以排序,但qsort 调用在这两种情况下是不同的。此外,sizeof(P) 在这两种情况下仍然是错误的。请参阅docs,尤其是size 参数。并且,请再次发布重现该问题的最少但完整的代码。
  • @dxiv 它需要保留一个指向结构的指针数组,在这种情况下 qsort 调用应该是什么?
  • 链接的例子有int arg1 = *(const int*)a;。现在将int 替换为struct d*

标签: c sorting struct qsort


【解决方案1】:

您的比较函数将接收指向数组成员的指针。由于数组包含struct d * 类型的元素,因此参数的类型为struct d **

考虑到这一点,您的比较函数应如下所示:

int usporedba(const void* a, const void* b) 
{
   const struct d *arg1 = *(const struct d **)a;
   const struct d *arg2 = *(const struct d **)b;

   if (!arg1 && !arg2) return 0;
   if (!arg1) return 1;
   if (!arg2) return -1;
   if (arg1->prio < arg2->prio) return -1;
   if (arg1->prio > arg2->prio) return 1;
   return 0;
}

此排序假定NULL 元素应位于数组的末尾。如果您希望它们在开头,则交换第二个和第三个条件的返回值。

【讨论】:

    【解决方案2】:

    编辑:我没有考虑给定代码中的错误。 (我之所以指定这个问题,是因为 cmets 让我看到您使用的是指向数组而不是数组的指针)


    我不确定您希望 qsort 对这些 NULL 值做什么。你一开始就想要它们吗?在末尾?还是你想让qsort 忽略它们?

    我看到了三种可能性:

    1. 如果所有的 NULL 值都在数组的末尾(或者如果将它们都放在数组的末尾相对容易),并且很容易知道有多少 NULL 值,那么当调用qsort,您可以将NULL 值的数量减去参数MAX_NUM
    2. 在您的比较函数中,检查 NULL 值:
    int compare(const void *p, const void *q)
    {
        if (!p && !q)
            return 0;
        if (!p)
            return 1; // or -1
        if (!q)
            return -1; // or 1
        ...
    }
    
    1. (不推荐,除非其他选项不可能) 如果您知道在您的情况下永远不会出现 prio 的值(例如 -2^31,即 -2147483648,或 2^31- 1 是 2147483647),那么您可以用占位符结构替换所有 NULL 值,其中 prio 是这个值,在 qsort 之后,您可以将这些占位符值重新替换为 NULL。 (在我看来,这个选项的效率低于其他选项)

    此外,您可以简单地执行以下操作,而不是比较两次并返回硬编码的 -1、0 或 1:

    int compare(const void *p, const void *q)
    {
        ...
        return l - r;
    }
    

    如果l &lt; r 将自动返回负值,如果l &gt; rl == r 的0 则自动返回正值。它也更简单:)

    【讨论】:

    • 这是一级间接关闭。它不工作,不能以这种方式工作。 NULL 情况是指p, q 指向的指针,而不是pq 本身。
    • 确实,我没有阅读 OP 给出的完整代码,只是专注于解决问题。我的方法需要额外的调整才能使用给定的代码。如果有人想帮助我并编辑我的答案,请随时。
    最近更新 更多