在排序时,我们通常写的函数只能排一种固定的类型,那有没有一种方法可以用来对所有的数据类型,进行排序呢?库函数中的qsort函数就可以实现这种排序。
首先qsort的函数参数有四个,第一个是数组的起始地址(即数组名),第二个是数组的大小(元素个数),第三个是数组中一个元素的大小(占几个字节),第四个是函数指针(指向所要调用的函数且这个被调用的函数类型和形参与函数指针一致为int (const void* e1, const void* e2))。
先举个例子:
#include<stdio.h>
#include<stdlib.h>
//实现一个比较整型的函数
int compare_int(const void* e1, const void* e2) {//为什么要写成void *呢?
return *(int*)e1 - *(int*)e2;
}
int main() {
int arr[10] = { 1,2,4,3,5,6,7,8,9,10 };
qsort(arr, 10, sizeof(arr[0]), compare_int);
for (int i = 0; i < sizeof(arr)/sizeof(arr[0]); i++)
{
printf("%d ", arr[i]);
}
return 0;
}
为什么函数形参那要写成void 呢?
因为qsort不知道你要比较什么类型的数据,你传给qsort的第四个实参只是另一个被调函数的地址。void类型的指针优点在于,可以接收任何类型的地址,缺点是你不能对它进行解引用,因为它自己都不知道自己是什么类型的,不知道解引用成什么数据。void指针可以指向任何类型的数据但是它本身的数据类型是void,如果你想使用这个指针就必须先将它强制转换成它指向的那个数据类型指针
对于你自己设计的那个函数,例如上面的int compare_int(const void e1, const void* e2)中的两个函数参数e1,e2,是不需要你来对它进行传参的,qsort内部会自动给它传参。
刚才上面讲到void型指针不能够解引用,那么当它作为参数传给你设计的那个函数时怎么进行比较呢?我们可以进行强制类型转换然后在解引用,因为我们此时已经知道比较的是什么类型的数据了。
再来对qsort函数进行一个总结:如果你要比较int类型的数据那么你就设计一个函数,函数的类型和参数与qsort的第四个参数函数指针指向的函数类型一致为int compare(const void* e1, const void* e2),因为传来的是指向int类型的空指针类型,如果你想使用指针就需要对它进行强转为它指向的数据类型然后解引用后比较,返回值为正数,0,负数,qsort会根据返回值来判断它们的大小。先设计函数为int compare(const void* e1, const void* e2)根据传来的空指针指向的什么类型强转就将它强转为它指向的类型指针然后解引用。
#include<stdio.h>
#include<stdlib.h>
//实现一个比较整型数据的函数
//int compare_int(const void* e1, const void* e2) {
// return *(int*)e1 - *(int*)e2;
//}
//
//void test1() {
// int arr[10] = { 1,2,4,3,5,6,7,8,9,10 };
// qsort(arr, 10, sizeof(arr[0]), compare_int);
// for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
// {
// printf("%d ", arr[i]);
// }
//}
struct Student
{
char name[20];
int age;
};
//int com_stu_age(const void* e1, const void* e2){
// return *(int*)e1 - *(int*)e2;//这是错误的,传过来的e1,e2,是指向结构体的指针,所以要先强制转换成结构体指针在进行解引用
// }
//实现一个比较结构体类型中年龄数据的函数
int com_stu_age(const void* e1, const void* e2) {
return ((struct Student*)e1)->age - ((struct Student*)e2)->age;//e1,e2指向的类型为结构体指针struct Student*
}
void test2() {
struct Student s[3] = { {"zhangsan",20},{"lisi",19},{"wanger",32} };
qsort(s, sizeof(s) / sizeof(s[0]), sizeof(s[0]),com_stu_age);
for (int i = 0; i < 3; i++)
{
printf("%d ", s[i].age);
}
}
int main() {
//test1();
test2();
return 0;
}
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct Student
{
char name[20];
int age;
};
//比较结构体类型中名字的函数
int com_stu_name(const void* e1, const void* e2) {
//在对char类型数据进行比较时,要使用strcmp函数,同时包含头文件#include<string.h>
return strcmp(((struct Student*)e1)->name, ((struct Student*)e2)->name);//e1,e2指向的类型为结构体指针struct Student*
}
void test2() {
struct Student s[3] = { {"zhangsan",20},{"lisi",19},{"wanger",32} };
qsort(s, sizeof(s) / sizeof(s[0]), sizeof(s[0]), com_stu_name);
for (int i = 0; i < 3; i++)
{
printf("%s ", s[i].name);
}
}
int main() {
//test1();
test2();
return 0;
}