27、回调函数

厨子大约 4 分钟C语言基础程序程序厨

视频讲解见:技术点讲解open in new window

在编码世界中,回调函数是一种强大的编程技术与思想,通过回调函数,程序在运行时可以动态地决定调用哪个函数。

这种机制在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函数,并将34作为参数传递给它。

回调函数的实现

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函数,你还可以传递multidiv函数等等。

回调函数的调用时机

回调函数的调用时机通常由被调用函数(即包含回调函数作为参数的函数)决定。被调用函数会在适当的时候(如事件发生时、条件满足时、异步操作完成时等)调用回调函数。

例如,在上面的process函数中,回调函数callbackprocess函数内部被调用,用于处理xy的值。

示例代码

下面代码展示了如何在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

练习

  1. 实现一个计算函数,该函数接受一个整数数组和一个回调函数作为参数。回调函数用于对每个数组元素进行操作(比如,计算每个元素的平方),并将操作后的结果存储回原数组。

进阶

  1. 理解回调函数的使用场景,理解模板方法设计模式,尝试将回调函数运用在模板方法设计模式中。
  2. 使用typedef重命名回调函数的声明,使其可读性更高。