文章目录
- 回调函数
- 什么是回调函数
- 回调函数的作用
- 库函数qsort
- 使用qsort函数排序整形
- 使用qsort函数排序结构体
- qsort函数模拟实现
- 说明
- 源码`and`说明
回调函数
什么是回调函数
回调函数就是⼀个通过函数指针调⽤的函数。
如果你把函数的指针(地址)作为参数传递给另⼀个函数,当这个指针被⽤来调⽤其所指向的函数时,被调⽤的函数就是回调函数。回调函数不是由该函数的实现⽅直接调⽤,⽽是在特定的事件或条件发⽣时由另外的⼀⽅调⽤的,⽤于对该事件或条件进⾏响应。
简单说,回调函数就是用函数指针也就是函数的地址来调用函数。
回调函数的作用
回调函数可以减少函数的冗余,并且可以使函数的功能更加丰富,实现泛型编程,我们之间从下面qsort的模拟实现中体会
库函数qsort
我们看一下qsort的官方描述
分析以下函数的参数,依次是:
- 数组首元素地址
- 数组元素个数
- 数组元素大小
- 自定义比较函数的地址
使用qsort函数排序整形
int cmp_int(const void* p1, const void* p2)
{return *(int*)p1 - *(int*)p2;
}
int main()
{int arr[] = { 2,4,3,5,9,8,6,7,1,0 };qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(arr[0]), cmp_int);return 0;
}
注意 自定义比较函数的参数类型是void*
,要先将地址强制类型转换成int*
再解引用
使用qsort函数排序结构体
#include<string.h>
int cmp_stu_by_age(const void* p1, const void* p2)
{return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name);
}
struct Stu
{char name[10];int age;
};
int main()
{struct Stu s[] = { {"zhangsan", 20}, {"lisi", 30}, {"wangwu", 15} };int sz = sizeof(s) / sizeof(s[0]);qsort(s, sz, sizeof(s[0]), cmp_stu_by_age);
}
注意 比较字符串时要用库函数strcmp
qsort函数模拟实现
说明
回顾我这个编程小白的排序技能库,似乎只会一种冒泡排序,所以下面模拟实现qsort
是在冒泡排序的基础上改进完成的
源码and
说明
主体部分
void bubble_sort_plus(void* base, size_t num, size_t size, void* cmp(const void*, const void*))
{for (int i = 0; i < num-1; i++){for (int j = 0; j < num - i - 1; j++){if (cmp((char*)base + j*size, (char*)base + (j+1)*size) > 0){Swap((char*)base + j * size, (char*)base + (j + 1) * size, size);}}}
}
注意
- 函数参数和库函数中的qsort类型相同
- 内层循环的判断条件
- 通过地址来调用用户自定义的比较函数,自定义的比较函数的参数,强制转换成char* 找到元素第 一个字节的地址,然后再加上每一个元素的宽度,即可访问数组中的元素
- 使用函数地址来调用函数,
cmp
函数是一个回调函数,使用户自定义函数类型,丰富了函数的功能
- 实现交换功能
- 由于不知道用户传递来的函数数据类型,因此只能先强制转换为
char*
类型的数据,通过一个一个的字节来访问元素
- 由于不知道用户传递来的函数数据类型,因此只能先强制转换为
Swap
函数
void Swap(char* p1, char* p2, size_t size)
{for (int i = 0; i < size; i++){char tmp = *p1;*p1 = *p2;*p2 = tmp;p1++;p2++;}
}
注意
- 函数参数直接用
char*
类型来接收 - 设计参数
size
,可以控制交换字节的个数 - 交换的原理是一个字节一个字节的交换
完