点击左上方蓝色“一口Linux”,选择“设为星标”
int*p1;char*p2;STRUCT*p3;// STRUCT为我们定义的结构体
下面我们来了解一下函数指针的概念和使用方法。
1. 概念
(相关资料图)
一般为了方便使用,我们会选择:
比如:
typedefint(*Fun1)(int);//声明也可写成int (*Fun1)(int x),但习惯上一般不这样。typedefint(*Fun2)(int,int);//参数为两个整型,返回值为整型typedefvoid(*Fun3)(void);//无参数和返回值typedefvoid*(*Fun4)(void*);//参数和返回值都为void*指针
2. 如何用函数指针调用函数
intFunc(intx);/*声明一个函数*/int(*p)(intx);/*定义一个函数指针*/p=Func;/*将Func函数的首地址赋给指针变量p*/p=&Func;/*将Func函数的首地址赋给指针变量p*/
赋值时函数 Func 不带括号,也不带参数。由于函数名 Func 代表函数的首地址,因此经过赋值以后,指针变量 p 就指向函数 Func() 代码的首地址了。
#include intMax(int,int);//函数声明intmain(void){int(*p)(int,int);//定义一个函数指针inta,b,c;p=Max;//把函数Max赋给指针变量p,使p指向Max函数printf("pleaseenteraandb:");scanf("%d%d",&a,&b);c=(*p)(a,b);//通过函数指针调用Max函数printf("a=%d\nb=%d\nmax=%d\n",a,b,c);return0;}intMax(intx,inty)//定义Max函数{intz;if(x>y){z=x;}else{z=y;}returnz;}
特别注意的是,因为函数名本身就可以表示该函数地址(指针),因此在获取函数指针时,可以直接用函数名,也可以取函数的地址。
p=Max 可以改成 p=&Maxc=(*p)(a,b) 可以改成 c=p(a,b)
3. 函数指针作为某个函数的参数
#include
#include //前加一个typedef关键字,这样就定义一个名为FunType函数指针类型,而不是一个FunType变量。
//形式同typedefint*PINT;
typedefvoid(*FunType)(int);
voidmyFun(intx);voidhisFun(intx);voidherFun(intx);voidcallFun(FunTypefp,intx);intmain(){callFun(myFun,100);//传入函数指针常量,作为回调函数callFun(hisFun,200);callFun(herFun,300);return0;}voidcallFun(FunTypefp,intx){fp(x);//通过fp的指针执行传递进来的函数,注意fp所指的函数有一个参数}voidmyFun(intx){printf("myFun:%d\n",x);}voidhisFun(intx){printf("hisFun:%d\n",x);}voidherFun(intx){printf("herFun:%d\n",x);}
4. 函数指针作为函数返回类型
有了上面的基础,要写出返回类型为函数指针的函数应该不难了,下面这个例子就是返回类型为函数指针的函数:
void(*func5(int,int,float))(int,int){...}
在开始讲解回调函数前,最后介绍一下函数指针数组。既然函数指针也是指针,那我们就可以用数组来存放函数指针。下面我们看一个函数指针数组的例子:
/*方法 1*/void(*func_array_1[5])(int,int,float);/*方法 2*/typedefvoid(*p_func_array)(int,int,float);p_func_arrayfunc_array_2[5];
我们先来看看百度百科是如何定义回调函数的:
结合这幅图和上面对回调函数的解释,我们可以发现,要实现回调函数,最关键的一点就是要将函数的指针传递给一个函数(上图中是库函数),然后这个函数就可以通过这个指针来调用回调函数了。注意,回调函数并不是C语言特有的,几乎任何语言都有回调函数。在C语言中,我们通过使用函数指针来实现回调函数。
回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
2. 为什么要用回调函数?
因为可以把调用者与被调用者分开,所以调用者不关心谁是被调用者。它只需知道存在一个具有特定原型和限制条件的被调用函数。
intCallback()// /<回调函数{//TODOreturn0;}intmain()// /<主函数{//TODOLibrary(Callback);// /<库函数通过函数指针进行回调//TODOreturn0;}
回调似乎只是函数间的调用,和普通函数调用没啥区别。
3. 怎么使用回调函数?
intCallback_1(inta)// /<回调函数1{printf("Hello,thisisCallback_1:a=%d",a);return0;}intCallback_2(intb)// /<回调函数2{printf("Hello,thisisCallback_2:b=%d",b);return0;}intCallback_3(intc)// /<回调函数3{printf("Hello,thisisCallback_3:c=%d",c);return0;}intHandle(intx,int(*Callback)(int))// /<注意这里用到的函数指针定义{Callback(x);}intmain(){Handle(4,Callback_1);Handle(5,Callback_2);Handle(6,Callback_3);return0;}
#include
#include /*****************************************函数指针结构体***************************************/
typedefstruct_OP
{
float(*p_add)(float,float);float(*p_sub)(float,float);float(*p_mul)(float,float);float(*p_div)(float,float);}OP;/*****************************************加减乘除函数***************************************/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=ADD;op->p_sub=SUB;op->p_mul=&MUL;op->p_div=&DIV;}/*****************************************库函数***************************************/floatadd_sub_mul_div(floata,floatb,float(*op_func)(float,float)){return(*op_func)(a,b);}intmain(intargc,char*argv[]){OP*op=(OP*)malloc(sizeof(OP));init_op(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));return0;}
/*********工作状态处理*********/typedefstruct{uint8_tmStatus;uint8_t(*Funtion)(void);//函数指针的形式}M26_WorkStatus_TypeDef;//M26的工作状态集合调用函数/************************************************>M26工作状态集合函数***********************************************/M26_WorkStatus_TypeDefM26_WorkStatus_Tab[]={{GPRS_NETWORK_CLOSE,M26_PWRKEY_Off},//模块关机{GPRS_NETWORK_OPEN,M26_PWRKEY_On},//模块开机{GPRS_NETWORK_Start,M26_Work_Init},//管脚初始化{GPRS_NETWORK_CONF,M26_NET_Config},//AT指令配置{GPRS_NETWORK_LINK_CTC,M26_LINK_CTC},//连接调度中心{GPRS_NETWORK_WAIT_CTC,M26_WAIT_CTC},//等待调度中心回复{GPRS_NETWORK_LINK_FEM,M26_LINK_FEM},//连接前置机{GPRS_NETWORK_WAIT_FEM,M26_WAIT_FEM},//等待前置机回复{GPRS_NETWORK_COMM,M26_COMM},//正常工作{GPRS_NETWORK_WAIT_Sig,M26_WAIT_Sig},//等待信号回复{GPRS_NETWORK_GetSignal,M26_GetSignal},//获取信号值{GPRS_NETWORK_RESTART,M26_RESET},//模块重启}/************************************************>M26模块工作状态机,依次调用里面的12个函数***********************************************/uint8_tM26_WorkStatus_Call(uint8_tStart){uint8_ti=0;for(i=0;i<12;i++){if(Start==M26_WorkStatus_Tab[i].mStatus){returnM26_WorkStatus_Tab[i].Funtion();}}return0;}
原文:https://blog.csdn.net/qq_41854911/article/details/121058935
精彩文章合集
文章推荐
点击左上方蓝色“一口Linux”,选择“设为星标”第一时间看干货文章...
中国经济加快复苏,不断提升海外投资者对华投资的信心。近日,众多...
4月的盘锦大地,一栋栋育苗棚里秧苗长势喜人,水稻春播即将开始。扛...
欢迎观看本篇文章,小勉来为大家解答以上问题。论语的作者是谁,孔...
半导体产业是全球最重要的制造业之一,同时也是能源消耗最大的行业...
1、岗位性津贴又称劳动性津贴,是指为了补偿职工在某些特殊劳动条件...
甘肃经济日报兰州讯(新甘肃·甘肃经济日报记者马如娟)“五一”黄...
刚刚过去的“五一”假期,被称作是“史上最火五一”。数据显示,浙...
30日,前俄总统儿童权利全权代表阿斯塔霍夫在一档电视节目中表示,...
采煤机是煤矿综采工作面的核心设备,就好比人的“心脏”,要根据现...
同样得夜晚,不一样的搏杀,难道你左手鞭炮,右手农药?翻仓放鞭炮...
欢迎观看本篇文章,小升来为大家解答以上问题。土豆炸酱面做法窍门...
欢迎观看本篇文章,小勉来为大家解答以上问题。是谁推翻了清朝,清...
1、{?如果你要的是这个符号!!用智能ABC就能打出来了v6的第9页第8个...
青岛日报社 观海新闻5月5日讯降雨结束后,今天岛城气温小幅回升,...
文|WBO烈酒商业观察团队编|肖海林创立于2014年11月的酒小二,最开始...
天赐材料:战略与可持续发展委员会工作细则(2023年5月)
据wind统计,北向资金9月累计成交184829亿元,成交净卖出113亿元。...
4月28日,以“城市更新,向数而行”为题的青岛市数字经济赋能实体产...
记者从贵州省兴义市林业部门了解到,5月4日17时左右,接兴义市捧乍...
近日山西汾酒集团主办的以“推动高质量致力新消费”为主题的论坛在...
5月5日,金辰股份发布公告称,公司本次向特定对象发行股票方案已经...
1、正红菇(RussulaVinosaLinolbl)属担层菌纲、伞菌目、红菇科、红菇...
午后朋友圈疯传21城棚改的消息,黑色系集体拉涨,双焦强势翻红。截...
就是找江西xx法务债务公司委托他们给我分期x延期处理 服务费
交易商品牌 产地交货地最新报价二苯甲烷 含量99%定州旭阳科技有限...
1、20个工作日更新一次。2、四种情形会被列入经营异常名录:企业未...
看到ff91量产,有的网友说,还真被这老小子折腾出来了。最有意思的...
今天来聊聊关于提前还款剩余贷款利率怎么计算,贷款利率怎么计算的...
中新网武汉5月5日电 (周翌雯)武汉海关所属武汉邮局海关5日通过互联...