什么是回调函数我们先来看看百度百科是怎么定义回调函数的:回调函数就是通过函数指针调用的函数。如果你把一个函数指针(地址)作为参数传递给另一个函数,当这个指针被用来调用它所指向的函数时,我们就说这是一个回调函数。回调函数不是由函数的实现者直接调用,而是在特定事件或条件发生时被另一方调用,用于响应事件或条件。这段话比较长,比较曲折。我用一张图来说明什么是回调:假设我们要用一个排序函数对数组进行排序,那么在主程序(Mainprogram)中,我们先遍历库,选择一个库排序函数(Libraryfunction).但是排序算法有很多,包括冒泡排序、选择排序、快速排序和归并排序。同时,我们可能还需要对特殊的对象进行排序,比如特定的结构。库函数会根据我们的需要选择一种排序算法,然后调用实现该算法的函数来完成排序工作。被调用的排序函数是回调函数(Callbackfunction)。结合这张图和上面对回调函数的解释,我们可以发现,要实现回调函数,最关键的一点就是将函数指针传递给一个函数(上图中的库函数),然后这个函数就可以通过这个指针调用回调函数。注意回调函数并不是C语言独有的,几乎任何语言都有回调函数。在C语言中,我们通过函数指针来实现回调函数。那个函数指针是什么?别着急,我们来看看什么是函数指针。什么是函数指针?函数指针也是指针的一种,但是它指向的不是一个整数,而是一个函数,而不是一个字符。在C语言中,每个函数编译后都存放在内存中,每个函数都有一个入口地址。根据这个地址,我们就可以访问和使用这个功能了。函数指针就是通过指向函数的入口来调用函数。函数指针的使用函数指针的定义函数指针虽然也是指针,但是它的定义方法看起来与其他指针有很大的不同。让我们看看它是如何定义的:/*方法1*/void(*p_func)(int,int,float)=NULL;/*方法2*/typedefvoid(*tp_func)(int,int,float);tp_funcp_func=空;这两个方法都定义了一个返回值为void类型的指针,一个参数为(int,int,float)的函??数指针。第二种方法是让函数指针更容易理解,尤其是在复杂的环境中;对于一般的函数指针,直接使用第一种方法即可。如果你以前没有见过函数指针,你可能会认为函数指针的定义很奇怪。为什么不是void()(int,int,float)*p_func而是void(*p_func)(int,int,float)这种形式?我不知道这个问题,也不必担心。花点时间了解一下它和普通指针的区别。如果它不起作用,请先记住它的形式。函数指针的赋值定义了函数指针后,我们需要对其进行赋值。我们有两种方法来分配函数指针:void(*p_func)(int,int,float)=NULL;p_func=&func1;p_func=func2;以上两种方法都是合法的。对于第二种方法,编译器会将func_2从void()(int,int,float)类型隐式转换为void(*)(int,int,float)类型,因此两种方法都有效。有关更详细的说明,您可以查看以下stackoverflow链接。使用函数指针调用函数因为函数指针也是指针,所以可以使用带有*的常规方法来调用函数。和函数指针的赋值一样,我们也可以使用两种方法:/*method1*/intval1=p_func(1,2,3.0);/*method2*/intval2=(*p_func)(1,2,3.0);方法一和我们平时直接调用函数是一样的,方法二是通过*获取函数指针的值,从而实现函数调用。将函数指针作为参数传递给函数函数指针和普通指针一样,我们可以把它作为函数的参数传递给函数,下面看看如何实现函数指针的参数传递:/*func3使用函数指针p_func作为其形参*/voidfunc3(inta,intb,floatc,void(*p_func)(int,int,float)){(*p_func)(a,b,c);}/*func4调用函数func3*/voidfunc4(){func3(1,2,3.0,func_1);/*或func3(1,2,3.0,&func_1);*/}函数指针用作函数的返回类型。有了上面的基础,返回类型应该写成函数指针的函数应该不难了。下面的例子是一个返回类型为函数指针的函数:void(*func5(int,int,float))(int,int){...}这里,func5以(int,int,float)作为参数开始,其返回类型为void(*)(int,int)。在C语言中,变量或函数的声明也是一道大题。如果你想了解更多关于声明的话题,可以参考我之前的文章《C专家编程》阅读笔记(第1-3章)。这本书的第三章用了整整一章来解释如何阅读和理解Clanguagedeclarations函数指针数组在开始讲解回调函数之前,最后介绍一下函数指针数组,由于函数指针也是指针,所以我们可以用数组来存储函数指针,我们来看一个函数数组的例子指针:/*方法1*/void(*func_array_1[5])(int,int,float);/*方法2*/typedefvoid(*p_func_array)(int,int,float);p_func_arrayfunc_array_2[5];以上两种方法都可以用来定义一个函数指针数组,它们定义了一个元素个数为5,类型为void(*)(int,int,float)的函??数指针数组。回调函数我们讲过前面讲了函数指针,现在回到正题,看看回调函数是怎么实现的。以下是四个算术运算的简单回调函数示例:#include#include/******************************************函数指针结构******************************************/typedefstruct_OP{浮动(*p_add)(浮动,浮动);浮动(*p_sub)(浮动,浮动);浮动(*p_mul)(浮动,浮动);浮动(*p_div)(浮动,浮动);}操作;/**********************************************加减乘除函数********************************************/floatADD(floata,floatb){returna+b;}floatSUB(floata,floatb){returna-b;}floatMUL(floata,floatb){returna*b;}floatDIV(floata,floatb){returna/b;}/*******************************************初始化函数指针********************************************/voidinit_op(OP*op){op->p_add=添加;op->p_sub=SUB;op->p_mul=&MUL;op->p_div=÷}/****************************************库函数*****************************************/floatadd_sub_mul_div(floata,floatb,浮动(*op_func)(float,float)){return(*op_func)(a,b);}intmain(intargc,char*argv[]){OP*op=(OP*)malloc(sizeof(OP));初始化操作(操作);/*直接使用函数指针调用函数*/printf("ADD=%f,SUB=%f,MUL=%f,DIV=%f\n",(op->p_add)(1.3,2.2),(*op->p_sub)(1.3,2.2),(op->p_mul)(1.3,2.2),(*op->p_div)(1.3,2.2));/*调用回调函数*/printf("ADD=%f,SUB=%f,MUL=%f,DIV=%f\n",add_sub_mul_div(1.3,2.2,ADD),add_sub_mul_div(1.3,2.2,SUB),add_sub_mul_div(1.3,2.2,MUL),add_sub_mul_div(1.3,2.2,DIV));返回0;}这个例子有点长,我会一步一步解释如何使用回调函数第一步是完成加减乘除。我们需要定义四个函数来实现加减乘除的运算功能。这些函数是:/*******************************************加法、减法、乘法和除法函数*******************************************/floatADD(floata,floatb){returna+b;}floatSUB(floata,floatb){returna-b;}floatMUL(floata,floatb){returna*b;}floatDIV(floata,floatb){returna/b;}第二步,我们需要定义四个函数指针,分别指向这四个函数:/******************************************函数指针结构***************************************/typedefstruct_OP{float(*p_add)(float,float);浮动(*p_sub)(浮动,浮动);浮动(*p_mul)(浮动,浮动);浮动(*p_div)(浮动,浮动);}操作;/*****************************************初始化函数指针**************************************/voidinit_op(OP*op){op->p_add=ADD;op->p_sub=SUB;op->p_mul=&MUL;op->p_div=÷}第三步,我们需要创建一个“库函数”。这个函数接受一个函数指针作为参数,通过它调用不同的函数:/****************************************库函数*****************************************/float添加_订阅_mul_div(floata,floatb,float(*op_func)(float,float)){return(*op_func)(a,b);}Step4当这些步骤完成后,我们就可以开始调用回调函数了添加:/*调用回调函数*/printf("ADD=%f,SUB=%f,MUL=%f,DIV=%f\n",add_sub_mul_div(1.3,2.2,op->p_add),add_sub_mul_div(1.3,2.2,op->p_sub),add_sub_mul_div(1.3,2.2,MUL),add_sub_mul_div(1.3,2.2,DIV));回调函数可以通过四个简单的步骤实现。在这四步中,我们甚至可以省略第二步,直接将函数名传入“库函数”,比如上面的乘除运算。回调函数的核心是函数指针。只要理解了函数指针,再去学习回调函数,真的是得心应手。小结本文主要讲一下函数指针和回调函数的使用方法。回调函数的核心是函数指针,所以我花了很多篇幅解释函数指针。对于回调函数的实现,我举了一个例子,希望这个例子可以帮助到你。回调函数非常重要。如果你连它都不知道,C语言真的不是入门。当然,即使知道也不要骄傲,因为C语言中有太多的东西需要我们去学习和实践。如果您觉得本文对您有帮助,请点赞支持,谢谢!