qsort 是 C 标准库 <stdlib.h> 中提供的一个强大且高效的快速排序函数,它的优点是通用性强,可以用来排序任何类型的数据(如整数、浮点数、结构体等),只要你能告诉它如何比较两个元素。

(图片来源网络,侵删)
核心要点
使用 qsort 最关键的一点是:你必须自己编写一个“比较函数”,这个函数告诉 qsort 如何判断两个元素的先后顺序。
函数原型
我们来看一下 qsort 在 <stdlib.h> 中的原型:
void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
这个函数看起来有点复杂,我们来逐个解析它的参数:
| 参数 | 类型 | 含义 |
|---|---|---|
base |
void * |
待排序数组的起始地址。void* 是一个通用指针,可以指向任何类型的数据。 |
nmemb |
size_t |
数组中元素的数量。 |
size |
size_t |
数组中单个元素的大小(以字节为单位),这个参数非常重要,因为它让 qsort 能够正确地在内存中移动元素。 |
compar |
int (*)(const void *, const void *) |
指向比较函数的指针,这是 qsort 的核心,你需要自己实现这个函数来定义排序规则。 |
比较函数
这是整个 qsort 用法的核心和难点,比较函数的原型是固定的:

(图片来源网络,侵删)
int compar(const void *a, const void *b);
工作原理:
qsort 会反复调用你的 compar 函数,每次传入数组中的两个元素的地址(a 和 b),你的函数需要根据这两个元素的关系,返回一个整数值:
| 返回值 | 含义 |
|---|---|
负数 (< 0) |
a 应该排在 b 前面。 |
零 (= 0) |
a 和 b 相等,它们的相对位置无所谓。 |
正数 (> 0) |
a 应该排在 b 后面。 |
类型转换:
由于 compar 函数的参数是 const void *,你不能直接对它们进行解引用(如 *a),你必须先将它们强制转换回你数组元素的原始指针类型,然后再解引用。
完整使用步骤
- 包含头文件:
#include <stdlib.h> - 定义比较函数:根据你的数据类型,编写一个符合上述规则的
compar函数。 - 准备数据:将待排序的数据放入一个数组中。
- 调用
qsort:传入数组的首地址、元素个数、单个元素大小和你的比较函数。
实例讲解
我们通过几个经典的例子来掌握 qsort 的用法。
示例1:对整数数组进行升序排序
这是最简单的例子。

(图片来源网络,侵删)
#include <stdio.h>
#include <stdlib.h> // 必须包含此头文件
// 1. 定义比较函数
// 参数 a 和 b 是数组中两个元素的地址 (void* 类型)
int compare_ints(const void *a, const void *b) {
// 将 void* 指针强制转换为 int* 指针,然后解引用获取值
int arg1 = *(const int*)a;
int arg2 = *(const int*)b;
// 实现升序排序
if (arg1 < arg2) return -1; // a < b, a 排在 b 前面
if (arg1 > arg2) return 1; // a > b, a 排在 b 后面
return 0; // a == b
}
int main() {
int arr[] = {10, 5, 8, 20, 3, 15};
int n = sizeof(arr) / sizeof(arr[0]);
printf("排序前: ");
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
printf("\n");
// 2. 调用 qsort
// base: arr (数组首地址)
// nmemb: n (元素个数)
// size: sizeof(int) (单个元素大小)
// compar: compare_ints (我们的比较函数)
qsort(arr, n, sizeof(int), compare_ints);
printf("排序后: ");
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
输出:
排序前: 10 5 8 20 3 15
排序后: 3 5 8 10 15 20
代码解析:
compare_ints函数接收两个const void*,将它们转成const int*,再解引用得到int值。- 通过比较这两个
int值,返回-1,0, 或1,实现了升序排序。
示例2:对浮点数数组进行降序排序
这个例子展示了如何改变排序规则(从升序变为降序)。
#include <stdio.h>
#include <stdlib.h>
// 比较函数,用于降序排序
int compare_floats_desc(const void *a, const void *b) {
float arg1 = *(const float*)a;
float arg2 = *(const float*)b;
// 实现降序排序
if (arg1 > arg2) return -1; // a > b, a 排在 b 前面
if (arg1 < arg2) return 1; // a < b, a 排在 b 后面
return 0;
}
int main() {
float arr[] = {3.14, 1.5, 9.8, 2.2, 5.0};
int n = sizeof(arr) / sizeof(arr[0]);
printf("排序前: ");
for (int i = 0; i < n; i++) {
printf("%.2f ", arr[i]);
}
printf("\n");
qsort(arr, n, sizeof(float), compare_floats_desc);
printf("排序后: ");
for (int i = 0; i < n; i++) {
printf("%.2f ", arr[i]);
}
printf("\n");
return 0;
}
输出:
排序前: 3.14 1.50 9.80 2.20 5.00
排序后: 9.80 5.00 3.14 2.20 1.50
示例3:对结构体数组进行排序(按年龄)
qsort 的真正威力在于排序复杂数据类型,比如结构体。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 定义一个学生结构体
typedef struct {
char name[50];
int age;
float score;
} Student;
// 比较函数:按年龄升序排序
int compare_by_age(const void *a, const void *b) {
// 将 void* 转换为 Student*,再解引用获取结构体
Student *studentA = (Student*)a;
Student *studentB = (Student*)b;
// 比较年龄
return (studentA->age - studentB->age);
}
int main() {
Student students[] = {
{"Alice", 20, 88.5},
{"Bob", 19, 92.0},
{"Charlie", 21, 85.5},
{"David", 19, 95.0}
};
int n = sizeof(students) / sizeof(students[0]);
printf("按年龄排序前:\n");
for (int i = 0; i < n; i++) {
printf("%s, %d, %.1f\n", students[i].name, students[i].age, students[i].score);
}
qsort(students, n, sizeof(Student), compare_by_age);
printf("\n按年龄排序后:\n");
for (int i = 0; i < n; i++) {
printf("%s, %d, %.1f\n", students[i].name, students[i].age, students[i].score);
}
return 0;
}
输出:
按年龄排序前:
Alice, 20, 88.5
Bob, 19, 92.0
Charlie, 21, 85.5
David, 19, 95.0
按年龄排序后:
Bob, 19, 92.0
David, 19, 95.0
Alice, 20, 88.5
Charlie, 21, 85.5
注意: return (studentA->age - studentB->age); 是一种简洁的写法,它利用了整数相减会得到负数、零或正数的特性,完美符合 compar 函数的要求。
常见陷阱与注意事项
- 忘记包含
<stdlib.h>:这是最常见的新手错误。 - 比较函数逻辑错误:特别是升序和降序的逻辑容易写反。升序时,小的在前,返回负数;降序时,大的在前,返回负数。
- 指针类型转换错误:确保将
void*转换成你数组元素的正确指针类型(如int*,Student*)。 size参数错误:size应该是sizeof(你的元素类型),sizeof(int),如果传错,qsort在内存中移动元素时会发生错位,导致程序崩溃或错误结果。nmemb参数错误:确保元素个数计算正确,通常是sizeof(数组) / sizeof(数组[0])。
qsort 是 C 语言中一个功能强大且必须掌握的排序工具,它的核心在于自定义比较函数,只要你能清晰地定义出两个元素之间的“大小”关系,你就可以使用 qsort 对任何数据类型进行高效的排序,记住它的四个参数,特别是 size 和 compar,就能灵活运用它了。
