C 语言中qsort函数介绍与正确使用实用指南
平时做技术实践时,很多问题不是概念不会,而是细节没串起来。拿“C 语言中qsort函数介绍与正确采用”来说,它看着像小点,放到项目里常会牵出环境、配置、兼容性和维护成本。下面按实际采用顺序,把思路、关键写法和容易踩坑的地方讲清楚,便于大家直接对照操作。
前言
qsort 是 C 标准库 中提供的通用排序函数,能够对任意类型的数组进行排序(通常内部采用更快排序,但标准同时未规定具体算法)。
1. 函数原型
#include <stdlib.h>
void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
参数说明
| 参数 | 含义 |
|---|---|
base | 指向待排序数组首元素的指针(void * 可接受任意类型) |
nmemb | 数组中元素的个数 |
size | 每个元素的字节大小(通常写 sizeof(元素类型)) |
compar | 比较函数的函数指针 |
得到值
无得到值,排序结果直接写回 base 指向的数组。
2. 比较函数
比较函数是 qsort 的核心,签名必须是:
int compar(const void *a, const void *b);
它需比较 a、b 指向的两个元素,得到值约定如下所示:
- 得到负数:
a应排在b前面 - 得到 0:两者相等(顺序不确定)
- 得到正数:
a应排在b后面
在比较函数内部,通常需先把 void * 强制转换为实际元素类型。
3. 采用示例
3.1 排序整数数组
#include <stdio.h>
#include <stdlib.h>
int cmp_int(const void *a, const void *b) {
int ia = *(const int *)a;
int ib = *(const int *)b;
return (ia > ib) - (ia < ib); /* 避免 ia - ib 溢出 */
}
int main(void) {
int arr[] = {5, 2, 9, 1, 5, 6};
size_t n = sizeof(arr) / sizeof(arr[0]);
qsort(arr, n, sizeof(int), cmp_int);
for (size_t i = 0; i < n; i++)
printf("%d ", arr[i]);
printf("n");
return 0;
}
注意:不要写成
return *(int*)a - *(int*)b;,当两个数相差很大时可能发生整数溢出,导致比较结果错误。
3.2 排序结构体数组
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char name[32];
int age;
} Person;
/* 先按年龄升序,年龄相同按姓名升序 */
int cmp_person(const void *a, const void *b) {
const Person *pa = (const Person *)a;
const Person *pb = (const Person *)b;
if (pa->age != pb->age)
return (pa->age > pb->age) - (pa->age < pb->age);
return strcmp(pa->name, pb->name);
}
int main(void) {
Person people[] = {
{"Alice", 30},
{"Bob", 25},
{"Carol", 30},
{"Dave", 20},
};
size_t n = sizeof(people) / sizeof(people[0]);
qsort(people, n, sizeof(Person), cmp_person);
for (size_t i = 0; i < n; i++)
printf("%s (%d)n", people[i].name, people[i].age);
return 0;
}
3.3 排序字符串指针数组
int cmp_str(const void *a, const void *b) {
/* 数组元素是 char*,所以 a、b 实际是 char** */
const char *const *sa = (const char *const *)a;
const char *const *sb = (const char *const *)b;
return strcmp(*sa, *sb);
}
int main(void) {
const char *words[] = {"banana", "apple", "cherry", "date"};
size_t n = sizeof(words) / sizeof(words[0]);
qsort(words, n, sizeof(char *), cmp_str);
for (size_t i = 0; i < n; i++)
printf("%sn", words[i]);
return 0;
}
这是新手最常出错的地方:字符串数组的元素类型是 char *,所以传给比较函数的是 char **。
4. 复杂度与特性
- 平均时间复杂度:O(n log n)
- 最坏时间复杂度:取决于具体实现,理论上可能是 O(n²)
- 空间复杂度:通常 O(log n)(递归栈)
- 稳定性:
qsort不保证稳定排序结合项目来看,。若需稳定排序,需自行附加原始下标作为次级比较键,或改用归同时排序等算法。
5. 注意事项与常用陷阱
- 整数溢出:比较函数里不要直接用
a - b,改用(a > b) - (a < b)。 - 严格弱序:比较函数必须满足严格弱序(反对称、传递),否则行为未定义。
- 不要修改元素:比较函数只应读取,不应写入
a、b指向的内容。 - 浮点数比较:若数组含
NaN,<、>比较均为假,排序结果可能异常,需特殊处理。 size_t是无符号类型:向qsort传元素个数和元素大小时不要传负数,否则会被转换为巨大的无符号数,导致越界。- 元素大小必须一致:
size必须是所有元素共同的字节大小,qsort不兼容变长元素。 - 类型转换保持 const:强制转换时保留
const限定(如const int *),避免意外写入。 - C11 的
qsort_s:部分实现(如 MSVC、C11 附录 K)提供带上下文参数的qsort_s,但可移植性差,一般仍用qsort。
6. 小结
qsort 借助 void * + 函数指针实现了对任意类型的通用排序,是 C 语言中“泛型编程”的经典范例。采用时记住三点:正确传入元素个数与元素大小、正确编写比较函数、注意整数溢出与类型转换,就能应对绝大多数排序场景。
落到代码里,总的来说,C语言中qSort函数的用法适合结合实际项目边做边理解。先抓住核心思路,再逐步补上细节和边界处理,最后效果会更稳定,也更容易复用。
游戏推荐
推荐专题
热门阅读
推荐下载
-
-
下载
- |
-
-
下载
- 《行尸走肉第一章》免安装中文汉化硬盘版下载
- 单机|436 MB
- 一款以动作冒险为主题的游戏
-
-
下载
- 《街头霸王X铁拳》免安装中文汉化硬盘版下载
- 单机|111MB
- 一款非常好玩的格斗游戏
-
-
下载
- |
-
-
下载
- 《暗黑破坏神3》免安装繁体中文正式版下载
- 单机|7630 MB
- 一款以角色扮演为主题的游戏
-
-
下载
- 《马克思佩恩3》免安装硬盘版下载
- 单机|27033 MB
- 一款以第三人称射击为主题的游戏