qsort的cmp函数_1_13

下面我把 qsortcmp(比较函数)讲到你能“自己写、自己改、自己查错”为止。重点讲:它到底在比较什么、参数是什么、返回值规则、为什么你写 return x>y 会错,以及常见几种写法。


1)cmp 的角色:qsort 全靠它决定顺序

qsort 本身不知道你要排序的是 int、结构体还是别的,它只做一件事:

反复取出数组里的两个元素地址,交给 cmp 问:谁该排前面?

所以 cmp 就是“裁判”。


2)cmp 的固定签名(形参为什么是 const void*

标准库规定比较函数必须长这样:

int cmp(const void* a, const void* b)

这两个参数 ab 是什么?

它们不是元素本身
它们是“数组元素的地址”

比如你排序的是:

int nums[] = {3, 1, 2};
qsort(nums, 3, sizeof(int), cmp);

那么某一次比较可能传入:

  • a 指向 nums[i]
  • b 指向 nums[j]

所以你必须把 void* 转回你真实的元素类型再解引用:

int x = *(const int*)a;
int y = *(const int*)b;

为什么是 const void*

  • const:告诉你不要在 cmp 里修改数组元素
  • void*:因为 qsort 要通用,类型不固定

3)cmp 的返回值规则(最关键,必须背)

cmp(a,b) 返回值含义:

  • < 0a 应该排在 b 前面(a < b)
  • = 0:两者相等(顺序无所谓)
  • > 0a 应该排在 b 后面(a > b)

这是 qsort 唯一认可的规则


4)为什么你写 return x > y; 会错?

你写的是:

return *((int*)ptr1) > *((int*)ptr2);

这只会返回:

  • 0(false)
  • 1(true)

问题在于:qsort 需要 负/零/正 三种情况,而你只给了 0/1

尤其是当 x < y 时你返回 0,qsort 会把它当成:

“x 和 y 相等”

这会导致:

  • 排序结果不稳定、甚至不正确
  • 很多情况下“看起来像排了”,但其实不保证

5)正确的 int 升序 cmp(推荐写法:不溢出)

✅ 最推荐写法

static int cmp_int(const void* a, const void* b) {
    int x = *(const int*)a;
    int y = *(const int*)b;
    return (x > y) - (x < y);   // 结果只可能是 1 / 0 / -1
}

为什么这么写好?

  • 不会出现 x - y 的溢出风险
  • 清晰且稳定

6)常见其它写法(知道即可)

写法 A:用 if

static int cmp_int(const void* a, const void* b) {
    int x = *(const int*)a;
    int y = *(const int*)b;
    if (x < y) return -1;
    if (x > y) return 1;
    return 0;
}

✅ 也完全正确,最直观。


写法 B:return x - y;(不推荐)

return (*(int*)a) - (*(int*)b);

❌ 可能溢出,比如:

  • x = INT_MAX
  • y = -1
    x - y 会溢出成负数,比较结果就错了。

7)降序怎么写?

只要把比较方向反过来:

static int cmp_int_desc(const void* a, const void* b) {
    int x = *(const int*)a;
    int y = *(const int*)b;
    return (y > x) - (y < x);
}

或者:

return (x < y) - (x > y);

8)排序结构体怎么写(面试常考)

假设:

typedef struct {
    int val;
    int idx;
} Node;

val 升序:

static int cmp_node_by_val(const void* a, const void* b) {
    const Node* x = (const Node*)a;
    const Node* y = (const Node*)b;
    return (x->val > y->val) - (x->val < y->val);
}

9)cmp 里最容易犯的 4 个坑(你要重点避开)

  1. ❌ 返回 x > y
  2. ❌ 忘记把 void* 转成真实类型
  3. ❌ 用 x - y 导致溢出
  4. ❌ 在 cmp 里修改数组元素(违反 const 语义)

10)你现在该如何“自测 cmp 是否正确”?

拿一个简单数组:

int a[] = {3, 2, 2, 1};

如果 cmp 正确,排序后一定是:

1 2 2 3

如果你用 return x > y,你会发现有时候“看似”排序了,但遇到重复值、特定输入时可能乱序甚至错误。


11)一句话总结(复试可以直接背)

qsort 的 cmp 接收的是两个元素地址(const void*),
必须强转并解引用得到真实值,
返回负/零/正来表示小于/等于/大于,从而决定排序顺序。


posted @ 2026-01-18 12:36  Leon_LL  阅读(0)  评论(0)    收藏  举报