回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外一方调用,对于该事件或条件进行相应。
qsort函数的使用
刚开始学习的时候,我们写的排序函数往往只适用于整型数组。而qsort函数的优点就是可用于给多种类型(整型、结构体等)进行排序。
qsort函数的形参有四个,分别是起始元素的地址、元素个数、元素的字节宽度、(用来比较大小的)函数指针
其中需要调用的函数指针是独立出来的,需要自己根据数据类型进行编写(需要用到强制类型转换)
//void qsort(void* base,int sz,int width,int (*cmp)(const void*,const void*))
用qsort函数实现整型数组的排序
int arr[]={9,8,7,6,5,4,3,2,1,0};
int cmp_int(const void* e1,const void* e2)//因为数据类型的不确定,所以用void*来接收
{
return *((int*)e1)-*((int*)e2);//因为此处是用来比较整型数据的大小的,所以强制类型转换为int后相减作为返回值
}
void qsort(arr, sizeof(arr)/sizeof(arr[0]) ,sizeof(arr[0]),int (*cmp_int)(const void*,const void*));
用qsort函数实现结构体的排序
struct Stu {
char name[20];
int age;
};
struct Stu s[3] = { {"zhangsan",20},{"lisi",50},{"wangwu",33} };
int cmp_stu_by_age(const void* e1, const void* e2)
{
return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}
int main()
{
int sz = sizeof(s) / sizeof(s[0]);
qsort(s, sz, sizeof(s[0]), cmp_stu_by_age);
int i = 0;
return 0;
}
用冒泡排序的方式来模拟实现qsort函数
由于不知道数据类型,我们可以优先强制转换为char类型,然后一个字节一个字节的交换
void Swap(char* buf1, char* buf2, int width)
{
int i = 0;
for (i = 0; i < width; i++)
{
char tmp = *buf1;
*buf1 = *buf2;
*buf2 = tmp;
buf1++;
buf2++;
}
}//用来交换数据
void bubble_sort(void* base, size_t sz, size_t width, int (*cmp)(const void*, const void*))
{
size_t i = 0;
for (i = 0; i < sz - 1; i++)
{
size_t j = 0;
for (j = 0; j < sz - 1 - i; j++)
{
if (cmp((char*)base + j * width , (char*)base + (j + 1) * width) > 0)
Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
//因为void*步长不确定,而参数中有数据字节的大小width,可以用j*width来表示
}
}
}
int main()
{
int sz = sizeof(s) / sizeof(s[0]);
bubble_sort(s, sz, sizeof(s[0]), cmp_stu_by_age);
return 0;
}
接下里通过在VS中调出监视窗口就可以看到排序后的结果。