qsort的cmp函数_1_13
下面我把 qsort 的 cmp(比较函数)讲到你能“自己写、自己改、自己查错”为止。重点讲:它到底在比较什么、参数是什么、返回值规则、为什么你写 return x>y 会错,以及常见几种写法。
1)cmp 的角色:qsort 全靠它决定顺序
qsort 本身不知道你要排序的是 int、结构体还是别的,它只做一件事:
反复取出数组里的两个元素地址,交给 cmp 问:谁该排前面?
所以 cmp 就是“裁判”。
2)cmp 的固定签名(形参为什么是 const void*)
标准库规定比较函数必须长这样:
int cmp(const void* a, const void* b)
这两个参数 a、b 是什么?
✅ 它们不是元素本身
✅ 它们是“数组元素的地址”
比如你排序的是:
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) 返回值含义:
< 0:a应该排在b前面(a < b)= 0:两者相等(顺序无所谓)> 0:a应该排在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_MAXy = -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 个坑(你要重点避开)
- ❌ 返回
x > y - ❌ 忘记把
void*转成真实类型 - ❌ 用
x - y导致溢出 - ❌ 在 cmp 里修改数组元素(违反 const 语义)
10)你现在该如何“自测 cmp 是否正确”?
拿一个简单数组:
int a[] = {3, 2, 2, 1};
如果 cmp 正确,排序后一定是:
1 2 2 3
如果你用 return x > y,你会发现有时候“看似”排序了,但遇到重复值、特定输入时可能乱序甚至错误。
11)一句话总结(复试可以直接背)
qsort 的 cmp 接收的是两个元素地址(const void*),
必须强转并解引用得到真实值,
返回负/零/正来表示小于/等于/大于,从而决定排序顺序。

浙公网安备 33010602011771号