文章目录
- 前言
- 一、回调函数是什么?
- 如何实现回调函数
- 二、回调函数的应用——qsort
- qsort排序各种类型的数据
- 总结
前言
前两章讲了指针的类型,数组传参和指针传参,还有函数指针和函数指针数组,接下来第三章讲回调函数
指针函数非常大的用途就是实现回调函数
一、回调函数是什么?
回调函数就是通过函数指针调用的函数。
如果把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
如何实现回调函数
下面的代码过于冗余
如果分装一个函数,调用它,能大大减少了敲代码工作量,这个函数就是回调函数
所以分装一个函数叫Calc,在使用加减乘除时调用这个函数
case 1:
Calc(Add);
break;
case 2:
Calc(Sub);
break;
case 3:
Calc(Mul);
break;
case 4:
Calc(Div);
break;
函数地址传给Calc函数,用函数指针接收
这个pf是函数指针,指向的参数是(int, int),返回类型是int
void Calc(int (*pf)(int, int))
具体代码如下
int Add(int x, int y)
{
return x + y;
}
int Sub(int x, int y)
{
return x - y;
}
int Mul(int x, int y)
{
return x * y;
}
int Div(int x, int y)
{
return x / y;
}
void menu()
{
printf("***************************\n");
printf("***** 1.add 2.sub ******\n");
printf("***** 3.mul 4.div ******\n");
printf("***** 0.exit ******\n");
printf("***************************\n");
}
void Calc(int (*pf)(int, int))
{
int x = 0;
int y = 0;
int ret = 0;
printf("请输入两个操作数:");
scanf("%d %d", &x, &y);
ret = pf(x, y);
printf("ret = %d\n", ret);
}
int main()
{
int input = 0;
int x = 0;
int y = 0;
int ret = 0;
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
Calc(Add);
break;
case 2:
Calc(Sub);
break;
case 3:
Calc(Mul);
break;
case 4:
Calc(Div);
break;
case 0:
printf("退出计算器\n");
break;
default:
printf("选择错误,重新选择\n");
break;
}
} while (input);
return 0;
}
过程如下:
不是直接调用Add函数,而是把Add函数传给pf指针函数,,通过pf函数指针去调用Add函数,实现计算,那么pf函数指针就是回调函数 。
作用: 回调函数更具有广泛性和通用性,代码不易写死,如果直接调用Add函数,代码就被固定住了,要想调用别的函数,那个代码就不适用了。
二、回调函数的应用——qsort
qsort 是标准库里的函数,用来排序
qsort函数怎么实现回调函数呢?
这就得说到冒泡排序了
一般冒泡排序是这样写的:
int main()
{
int arr[10] = { 9,8,7,6,5,4,3,2,1,0 };
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
for (i = 0; i < sz - 1; i++)
{
int j = 0;
for (j = 0; j < sz - 1 - i; j++)
{
if (arr[j] > arr[j + 1])
{
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
}
这如果要排结构体,浮点型等其他类型的数据呢,这个代码就存在一定的问题了,只适用于整型的排序,形式固定住了,不灵活不广泛。
那有没有一种写一个排序函数,适用于任何类型呢?
qsort函数就能解决这个问题
qsort排序各种类型的数据
qsort函数的特点
1.快速排序的方法
2.适合于任意类型数据的排序
- 在cplusplus网站上搜索 qsort,可以看到qsort有四个参数:
四个函数的意思是:
void qsort(
void* base
,//指向需要排序的数组的第一个元素
size_t num
,//排序的元素个数
size_t size
,//一个元素的大小,单位是字节
int(*cmp)(const void*, const void*)
);//函数指针类型-这个函数指针指向的函数,能够比较base指向数组中的两个元素
用qsort排序整型
根据上面四个参数,写出下面这段代码
- 最后一个参数空出来没有写,是因为这里涉及到一些重要的知识点
第四个参数是要写一个函数,能够比较base指向数组中的两个元素,并把结果返回。 那么就写一个函数叫cmp_int,参数就是cplusplus网站上qsort函数给的两个参数
代码如下:
int cmp_int(const void* p1, const void* p2)
- 写完了函数,怎么比较两个数呢?
在cplusplus网站上找到计算方法如下:
当p1指向的值小于p2指向的值时,返回小于0的数字;
当p1指向的值等于p2指向的值时,返回0;
当p1指向的值大于p2指向的值时,返回大于0的数字;
那么就让p1p2两个数作差,把结果返回去。
但这里还涉及到一些知识:
一个热知识::void* 的指针是无具体类型的指针。
void* 类型的指针可以接收任意类型的地址
在函数参数这里用void* 的好处就是,广泛性,什么类型的数据排序都能接收,编程不会报警告。
但这种类型的指针不能直接解引用,也不能直接进行指针运算。所以在比较两个数大小时,需要强制类型转换。
意思就是要排序什么类型,就强制类型转换什么类型
比如:当要比较整型数据时,p1和p2要强制类型转换成整型,当比较浮点型数据时,p1和p2强制类型转换成浮点型。
代码如下:
int cmp_int(const void* p1, const void* p2)
{
return (*(int*)p1 - *(int*)p2);
}
- 最后把结果打印出来
分装一个print函数
参数是整型数组和数组大小
循环打印每个元素
void print(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
}
完整代码如下:
#include<stdlib.h>
int cmp_int(const void* p1, const void* p2)
{
return (*(int*)p1 - *(int*)p2);
}
void print(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
}
test1()
{
int arr[10] = {9,8,7,6,5,4,3,2,1,0};
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr,sz,sizeof(arr[0]),cmp_int);
print(arr, sz);
}
int main()
{
test1();
return 0;
}
注意:qsort 函数的头文件是 #include<stdlib.h>
用qsort 排序结构体
年龄比较大小
#include<stdio.h>
#include<stdlib.h>
struct Stu
{
char name[20];
int age;
};
int cmp_stu_by_age(const void* p1, const void* p2)
{
return ((struct Stu*)p1)->age - ((struct Stu*)p2)->age;
}
void print(struct Stu arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i].age);
}
}
void test2()
{
struct Stu arr[] = { {"zhangsan",20},{"lisi",50},{"wangwu",15} };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);
print(arr,sz);
}
int main()
{
test2();
return 0;
}
姓名比较大小
#include<stdio.h>
#include<stdlib.h>
struct Stu
{
char name[20];
int age;
};
int cmp_str_stu_by_name(const void* p1, const void* p2)
{
return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name);
}
//名字比较不能相减,名字是字符串,字符串比较大小用strcmp
void print(struct Stu arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%s ", arr[i].name);
}
}
void test3()
{
struct Stu arr[] = { {"zhangsan",50},{"lisi",15},{"wangwu",30} };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), cmp_str_stu_by_name);
print(arr, sz);
}
总结
本章讲了回调函数的含义,如何实现回调函数和qsort排序各种类型的数据的内容,希望对您有帮助!