C语言 qsort 函数用法详解与模拟实现
本文详解C语言标准库函数qsort的用法,涵盖整型、字符串、浮点数及结构体的排序技巧。通过自定义比较函数解决通用排序问题,并提供基于冒泡思想的通用排序模拟实现,帮助深入理解指针操作与泛型编程原理。
一、qsort 函数简介与参数解析
qsort是C语言标准库提供的通用排序函数,底层通常采用快速排序算法。它位于头文件 stdlib.h中,能够对任意类型的数组进行排序。
函数原型如下:
void qsort(void *base, size_t num, size_t size,
int (*compar)(const void *, const void *));第1步:理解参数含义
void *base:指向待排序数组的第一个元素的地址(起始位置)。size_t num:数组中元素的总个数。size_t size:每个元素占用的字节数。int (*compar)(const void *, const void *):比较函数的指针。该函数用于定义两个元素的比较规则,其返回值决定排序顺序:
| 返回值 | 条件 |
|---|---|
| > 0 | 第一个参数大于第二个参数 |
| < 0 | 第一个参数小于第二个参数 |
| = 0 | 两个参数相等 |
注意:由于传入的比较函数接收的是 const void * 类型指针,无法直接解引用或运算,必须强制转换为具体数据类型的指针。
二、qsort 函数的常见应用场景
1. 整型数组排序
对整数数组进行升序排序。核心在于编写一个针对整型的比较函数。
#include <stdio.h>
#include <stdlib.h>
int cmp_int(const void* e1, const void* e2) {
// 将 void* 强转为 int* 并解引用获取值
return *((int*)e1) - *((int*)e2);
}
int main() {
int arr[] = { 7,8,9,4,5,6,1,2,3,10 };
int sz = sizeof(arr) / sizeof(arr[0]);
// base传数组名(首元素地址),num为元素个数,size为单个元素字节数
qsort(arr, sz, sizeof(int), cmp_int);
for (int i = 0; i < sz; i++) {
printf("%d ", arr[i]); // 输出:1 2 3 4 5 6 7 8 9 10
}
return 0;
}2. 字符串(字符数组)排序
对字符数组按ASCII码升序排序。需注意计算长度时应使用 strlen,因为 sizeof 会包含结尾的空字符 '\0'。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int cmp_char(const void* e1, const void* e2) {
return strcmp((char*)e1, (char*)e2);
}
int main() {
char arr[] = "badecf";
int sz = strlen(arr); // 不包含 '\0'
qsort(arr, sz, sizeof(char), cmp_char);
printf("%s\n", arr); // 输出:abcdef
return 0;
}3. 字符串指针数组按长度排序
当数组元素是指针(如 char*)时,比较函数需先解引用指针得到字符串地址,再计算长度进行比较。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int cmp_strlen(const void* e1, const void* e2) {
// e1/e2 是 char** 类型,解引用后得到 char* 地址
return strlen(*(char**)e1) - strlen(*(char**)e2);
}
int main() {
char* arr[] = { "abc", "abcd", "abcdef" };
int sz = 3;
qsort(arr, sz, sizeof(char*), cmp_strlen);
for (int i = 0; i < sz; i++) {
printf("%s\n", arr[i]); // 按长度从短到长输出
}
return 0;
}4. 浮点型数组排序
浮点数比较不能直接相减后转 int,因为精度丢失会导致错误结果。应判断差值是否大于/小于0。
#include <stdio.h>
#include <stdlib.h>
int cmp_float(const void* e1, const void* e2) {
float val1 = *(float*)e1;
float val2 = *(float*)e2;
if (val1 > val2) return 1;
else if (val1 < val2) return -1;
else return 0;
}
int main() {
float arr[] = { 12.01f, 12.03f, 12.09f };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(float), cmp_float);
for (int i = 0; i < sz; i++) {
printf("%f ", arr[i]);
}
return 0;
}5. 结构体类型排序
可根据结构体成员的不同类型分别编写比较函数,例如按年龄(整型)或姓名(字符串)排序。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct stu {
char name[20];
int age;
};
// 按年龄排序
int cmp_age(const void* e1, const void* e2) {
return ((struct stu*)e1)->age - ((struct stu*)e2)->age;
}
// 按姓名排序
int cmp_name(const void* e1, const void* e2) {
return strcmp(((struct stu*)e1)->name, ((struct stu*)e2)->name);
}
int main() {
struct stu s[] = { {"zhangsan",21},{"lisi",20},{"wangwu",52} };
int sz = sizeof(s) / sizeof(s[0]);
// 选择按年龄排序
qsort(s, sz, sizeof(struct stu), cmp_age);
for (int i = 0; i < sz; i++) {
printf("%s %d\n", s[i].name, s[i].age);
}
return 0;
}三、用冒泡排序模拟实现通用排序功能
为了深入理解 qsort 的泛型原理,我们可以利用内存字节交换的方式,结合冒泡排序算法实现一个通用的排序函数 qsort_bubble。
1. 核心思路
- 字节交换:由于处理的是
void*,无法直接按数据类型交换。需要逐字节(byte by byte)交换,次数由元素宽度width决定。 - 地址偏移:在遍历数组时,通过
(char*)base + index * width定位当前和相邻元素的起始地址。 - 比较逻辑复用:比较函数保持不变,只需传入对应的地址即可。
2. 代码实现
#include <stdio.h>
#include <string.h>
struct stu {
char name[20];
int age;
};
int cmp_age(const void* e1, const void* e2) {
return ((struct stu*)e1)->age - ((struct stu*)e2)->age;
}
// 逐字节交换函数
void Swap(char* buf1, char* buf2, int width) {
for (int i = 0; i < width; i++) {
char tmp = *buf1;
*buf1 = *buf2;
*buf2 = tmp;
buf1++;
buf2++;
}
}
// 通用冒泡排序实现
void qsort_bubble(void* base, int sz, int width, int(*cmp)(const void*, const void*)) {
for (int i = 0; i < sz - 1; i++) {
for (int j = 0; j < sz - 1 - i; j++) {
// 计算相邻两个元素的地址
char* elem1 = (char*)base + j * width;
char* elem2 = (char*)base + (j + 1) * width;
// 调用比较函数
if (cmp(elem1, elem2) > 0) {
Swap(elem1, elem2, width);
}
}
}
}
int main() {
struct stu s[] = { {"zhangsan",21},{"lisi",20},{"wangwu",52} };
int sz = sizeof(s) / sizeof(s[0]);
// 打印排序前
for (int i = 0; i < sz; i++) {
printf("%s %d\n", s[i].name, s[i].age);
}
// 调用自定义通用排序
qsort_bubble(s, sz, sizeof(struct stu), cmp_age);
printf("\n--- Sorted ---\n");
// 打印排序后
for (int i = 0; i < sz; i++) {
printf("%s %d\n", s[i].name, s[i].age);
}
return 0;
}以上就是C语言中qsort函数用法及用冒泡排序实现的详细内容,更多关于C语言 qsort泛型排序的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













