27、回调函数
视频讲解见:技术点讲解
在编码世界中,回调函数是一种强大的编程技术与思想,通过回调函数,程序在运行时可以动态地决定调用哪个函数。
这种机制在C语言中通过函数指针实现,上层代码能够将一段代码(函数)传递给底层模块,底层模块在适当的时候调用这段代码。
基本概念理解
1. 回调函数是一种通过函数指针调用的函数
回调函数本质上是一个函数,但它的调用不是直接通过函数名,而是通过函数指针来实现的。这就意味着函数可以在运行时被动态地选择后调用。
2. 回调函数的思想&机制是上层代码将一段代码传递给底层模块,由底层模块在适当的时候调用
3. 回调函数通常用于事件处理、异步编程等场景
常见的场景就是图形用户界面(GUI)编程中,当用户点击按钮时,操作系统会调用应用程序提供的回调函数来处理这个事件,异步编程中也常用回调函数。
函数指针的使用
1. 如何声明函数指针变量
函数指针的声明与普通变量的声明类似,但需要在类型前加上一个星号(*)来表示这是一个指针,并且需要指定函数返回值的类型和参数的类型。
例如,一个返回int
类型并接受两个int
类型参数的函数指针可以声明为:
typedef int (*FuncPtr)(int, int);
这里,FuncPtr
是一个新的类型名,表示一个指向返回int
并接受两个int
参数的函数的指针。
2. 如何将函数地址赋给函数指针变量
将函数地址赋给函数指针变量很简单,只需使用函数名即可。例如:
int add(int a, int b) {
return a + b;
}
FuncPtr fp = add;
这里,fp
是一个FuncPtr
类型的变量,它被初始化为指向add
函数的指针。
3. 如何通过函数指针调用函数
通过函数指针调用函数与通过函数名调用函数类似,但需要使用函数指针变量名加上圆括号和参数。例如:
int result = fp(3, 4);
这里,fp(3, 4)
调用的是add
函数,并将3
和4
作为参数传递给它。
回调函数的实现
1. 设计包含回调函数作为参数的函数接口
设计包含回调函数作为参数的函数接口时,需要在函数原型中指定回调函数指针的类型。例如:
void process(int x, int y, FuncPtr callback) {
// ... 执行一些操作 ...
int result = callback(x, y);
// ... 使用回调函数的返回值进行进一步处理 ...
}
这里,process
函数接受两个整数参数和一个回调函数指针callback
。
2. 编写调用包含回调函数参数的函数,并传递合适的回调函数
调用包含回调函数参数的函数时,需要传递一个符合回调函数指针类型要求的函数名。例如:
int main() {
process(3, 4, add);
return 0;
}
这里,add
函数被作为回调函数传递给process
函数,你还可以传递multi
、div
函数等等。
回调函数的调用时机
回调函数的调用时机通常由被调用函数(即包含回调函数作为参数的函数)决定。被调用函数会在适当的时候(如事件发生时、条件满足时、异步操作完成时等)调用回调函数。
例如,在上面的process
函数中,回调函数callback
在process
函数内部被调用,用于处理x
和y
的值。
示例代码
下面代码展示了如何在C语言中使用回调函数:
#include <stdio.h>
// 声明回调函数类型
typedef int (*FuncPtr)(int, int);
// 示例回调函数
int add(int a, int b) {
return a + b;
}
// 包含回调函数参数的函数
void process(int x, int y, FuncPtr callback) {
printf("Processing...\n");
int result = callback(x, y);
printf("Result: %d\n", result);
}
int main() {
// 调用包含回调函数参数的函数,并传递合适的回调函数
process(3, 4, add);
return 0;
}
运行此代码将输出:
Processing...
Result: 7
练习
- 实现一个计算函数,该函数接受一个整数数组和一个回调函数作为参数。回调函数用于对每个数组元素进行操作(比如,计算每个元素的平方),并将操作后的结果存储回原数组。
进阶
- 理解回调函数的使用场景,理解模板方法设计模式,尝试将回调函数运用在模板方法设计模式中。
- 使用
typedef
重命名回调函数的声明,使其可读性更高。
