C语言标准库qsort函数用法详解与实战
了解C语言标准库中qsort函数的使用方法,掌握void*通用指针的转换逻辑及cmp回调函数的编写,适用于整型、浮点型和结构体数据的通用快速排序。
理解qsort函数与void*指针机制
qsort源自stdlib.h,基于快速排序算法实现。其核心优势在于能够处理任意数据类型的数据排序。这一能力依赖于void*类型指针——它能接收任何数据类型的地址,但无法直接解引用或进行加减运算,因为其不包含目标对象的大小信息。
#include <stdio.h>
int main()
{
int a = 10;
char ch = 'w';
void* p = &a;
p = &ch;
return 0;
}
在qsort的应用场景中,正是通过强制类型转换和重新解引用来解决这一“不可知大小”的问题。
qsort函数参数详解
qsort的标准原型如下:
void qsort(void* base, size_t num, size_t width,
int (*cmp)(const void*, const void*));
各参数的实际含义:
- void* base (数组首地址):待排序数组的首地址。可直接传入数组名或指向该数组的指针。
- size_t num (元素数量):数组的长度。计算方式通常为
sizeof(arr) / sizeof(arr[0])。 - size_t width (元素字节数):单个元素占用的内存字节数。通常使用
sizeof(arr[0])获取。 - int (*cmp)(...) (比较函数指针):定义排序规则的核心回调函数。它接收两个待比较元素的地址(
e1和e2),返回一个整数值决定顺序:- 返回 < 0:e1排在e2之前。
- 返回 > 0:e1排在e2之后。
- 返回 0:两者相等,相对位置不变。
为了安全排序并防止函数内部修改源数据,比较函数参数通常声明为const void*。
实战:不同数据类型排序示例
第1步:整型数组排序
针对整型,比较函数的核心是将void*强制转换为int*,然后解引用相减实现升序排列。
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
int cmp_int(const void* e1, const void* e2)
{
return *(int*)e1 - *(int*)e2;
}
int main()
{
int arr[10] = { 3, 4, 1, 2, 7, 8, 9, 5, 6, 0 };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), cmp_int);
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
//
return 0;
}
第2步:浮点数排序与精度控制
由于浮点数直接相减存在精度丢失风险且不能保证结果严格符合整数比较要求,稳妥的做法是转换为整型逻辑判断或使用条件分支。这里演示一种常见的类型转换写法(需注意精度截断问题):
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
int cmp_float(const void* e1, const void* e2)
{
// 注意:强转int可能损失精度,生产环境建议用差值判0法
return (int)(*(float*)e1 - *(float*)e2);
}
int main()
{
float arr[6] = { 2.0f, 2.3f, 4.5f, 5.0f, 8.0f, 9.0f };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), cmp_float);
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%.2f ", arr[i]);
}
//
return 0;
}
第3步:结构体数据的多维度排序
对于自定义结构体,可按字段灵活定制比较策略。
按年龄排序: 将地址转为结构体指针后直接访问字段进行减法比较。
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
struct stu
{
char name[20];
int age;
char sex[10];
};
// 按年龄升序
int cmp_stu_by_age(const void* e1, const void* e2)
{
return ((struct stu*)e1)->age - ((struct stu*)e2)->age;
}
int main()
{
struct stu s[3] = { {"zhangsan",30,"man"},{"lisi",20,"man"},{"ruhua",18,"woman"}};
int sz = sizeof(s) / sizeof(s[0]);
qsort(s, sz, sizeof(s[0]), cmp_stu_by_age);
int i;
for (i = 0; i < sz; i++)
{
printf("%s %d %s\n", s[i].name, s[i].age, s[i].sex);
}
//
return 0;
}
按姓名排序: 利用strcmp函数比较字符串内容。若需降序则反转参数位置。
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct stu
{
char name[20];
int age;
char sex[10];
};
int cmp_stu_by_name(const void* e1, const void* e2)
{
return strcmp(((struct stu*)e1)->name, ((struct stu*)e2)->name);
}
int main()
{
struct stu s[3] = { {"zhangsan",30,"man"},{"lisi",20,"man"},{"ruhua",18,"woman"}};
int sz = sizeof(s) / sizeof(s[0]);
qsort(s, sz, sizeof(s[0]), cmp_stu_by_name);
int i;
for (i = 0; i < sz; i++)
{
printf("%s %d %s\n", s[i].name, s[i].age, s[i].sex);
}
//
return 0;
}
总结
qsort的学习关键在于理解泛型排序背后的指针操作机制。熟练编写cmp回调函数(将void*转型并比较返回值)是使用的核心。只要掌握了这种模式,无论是基本类型还是复杂结构体,都能轻松应对排序需求。
以上就是C语言库函数中qsort()的详细应用说明,更多关于C语言高级编程的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













