当前位置: 首页 > 科技观察

再说说指针和函数

时间:2023-03-19 10:09:37 科技观察

pointerfunction指针函数,从名字上看它本质上就是一个函数。指针函数:返回类型为指针的函数。函数声明如下:int*plusfunction(inta,intb);当然也可以写成如下格式:int*plusfunction(inta,intb);让指针标记*粘在int上,和函数名f分开,这样看起来更清晰,plusfunction是函数名,返回值类型是int类型的指针。指针函数是一个普通的函数,只是因为它的函数返回值是一个指针。#include#includeint*plusfunction(inta,intb);intmain(){int*p=NULL;p=plusfunction(1,2);printf("*p是%d\n",*p);免费(p);return(0);}int*plusfunction(inta,intb){int*p=(int*)malloc(sizeof(int));*p=a+b;return(p);}这是一个简单指针函数的例子。运行结果如下。本文代码运行在VScode平台,使用方法《使用VScode调试C语言》。但是我有一个疑问,使用指针函数有什么好处,而且函数输入是指针???#include#includevoidplusfunction(inta,intb,int*p);intmain(){int*p=NULL;p=(int*)malloc(sizeof(int));加函数(1,2,p);printf("*p是%d\n",*p);免费(p);return(0);}voidplusfunction(inta,intb,int*p){*p=a+b;}这样执行是没问题的,当然我也发现了指针函数的好处就是a函数可以用作另一个函数的输入参数。测试函数(加函数(1,2));此时,使用第二种方法,用指针作为函数输入参数是不行的。还有,在使用指针作为函数参数之前,需要向指针申请内存,而指针函数则不需要。除了这两点,在日常的开发中,我还真没有发现指针函数的“优势”,这让我觉得一定要用指针函数来实现某个功能,或者之后的代码会更干净,可读性更好用指针函数实现。函数指针函数指针,本质上他是一个指针,而不是一个函数。C语言中的一些概念是一脉相承的。在之前的推文《指针与数组》中,数组指针和指针数组的概念更有效的帮助大家理解函数指针和指针函数。函数指针指的是一个指针,但是这个指针指向的函数不是普通的基本数据类型或者类对象。函数指针定义如下:int(*f)(inta,intb);//函数指针的声明和指针函数的对比可以看出,函数指针和指针的最大区别function是函数指针的函数名是指针,即函数名前有一个指针类型标志模型“*”。注意指针函数和函数指针表示方法的区别,不要混淆。最简单的区分方法就是看函数名前面的指针*是不是用中括号()括起来的,如果是括起来的就是函数指针,否则就是指针函数。当然,函数指针的返回值也可以是指针。简单的函数调用示例:#includevoidMyFun(inta);intmain(){MyFun(10);return(0);}voidMyFun(inta){printf("ais%d\n",a);}这是一个很简单的函数调用,其实也可以写成下面的格式:#包括voidMyFun(inta);intmain(){(*MyFun)(10);return(0);}voidMyFun(inta){printf("ais%d\n",a);}这段代码运行正常,也就是说(*MyFun)(10);它与MyFun(10)相同;这里强烈推荐没看过《指针与数组》的同学先看看。教材和资料中都提到数组名是一个常量指针,指向数组的第一个数据。从上面的例子来看,函数名似乎也是一个“常量指针”。在数组中,可以将数组名赋给一个指针,然后通过指针访问数组的内容,那么我们就可以定义一个函数指针,将函数名赋给函数指针,通过这个函数调用函数指针。#includevoidMyFun(inta);/*这个声明也可以写成:voidMyFun(int)*/void(*FunP)(int);/*也可以声明成void(*FunP)(intx),但通常不是约定俗成的。*/intmain(){FunP=MyFun;*乐趣P(10);return(0);}voidMyFun(inta){printf("ais%d\n",a);}在第7行函数指针前加*相当于取指针的值,这里理解为取出MyFun函数。然后更进一步:#includevoidMyFun(inta);/*这个声明也可以写成:voidMyFun(int)*/void(*FunP)(int);/*也可以声明为void(*FunP)(intx),但一般不会这样。*/intmain(){FunP=MyFun;乐趣P(10);return(0);}voidMyFun(inta){printf("ais%d\n",a);}对,把FunP放在前面不带*号也可以运行。上面的示例代码是C语言中最常见的函数指针形式。前面的例子只是为了让你更好地理解函数指针。在实际开发中,只需要使用final也是最常见的函数指针形式即可。否则,其他程序员对代码中以前的形式不是很熟悉,就会变成“秀操作”。虽然不影响运行,但是会降低代码的可读性。typedef的介绍C语言中typedef关键字的作用:复杂的声明定义简单的别名。显然,我们上面描述的函数指针是一个比较复杂的类型,使用typedef关键字可以简化函数指针的定义。#includevoidMyFun(inta);/*这条语句也可以写成:voidMyFun(int)*/typedefvoid(*FunType)(int);/*这只是定义一个函数指针类型*/FunTypeFunP;/*然后使用FunType类型声明全局FunP变量*/intmain(){FunP=MyFun;乐趣P(10);return(0);}voidMyFun(inta){printf("ais%d\n",a);}强烈推荐使用typedef和函数指针的组合,这是最常用的方式,也是a大家都能看懂的通用操作。C语言教程中,typedef用于取别名,形式为:typedefoldnamenewname;确实是一样的,但是在为函数指针类型、数组类型等定义别名时需要特别区分,如:typedefcharARRAY20[20];ARRAY20a1,a2;/*相当于chara1[20],a2[20];*/typedefvoid(*FunType)(int);/*这里只是定义了一个函数指针Type*/FunTypeFunP;/*然后用FunType类型声明全局FunP变量*/别问我为什么,因为我也不知道。当然,这并不意味着你需要使用typedef来定义函数指针。一般如果在结构体中使用函数指针,就不会使用typedef,如下:typedefstruct{uint8_tdata;void(*FunP)(int);}Mode_Typedef;以上都是个人建议,没有优劣之分,大家可以根据自己的习惯来做。函数指针作为输入参数函数指针变量既然是变量,当然也可以作为函数的参数。因此,您还应该了解函数指针是如何传递和用作函数参数的。示例代码如下:#includevoidMyFun1(intx);voidMyFun2(intx);voidMyFun3(intx);typedefvoid(*FunType)(int);/*②。定义一个函数指针类型FunType,与①函数类型一致*/voidCallMyFun(FunTypefp,intx);intmain(intargc,char*argv[]){CallMyFun(MyFun1,10);/*⑤.通过CallMyFun函数调用三个函数不同的函数*/CallMyFun(MyFun2,20);CallMyFun(MyFun3,30);}voidCallMyFun(FunTypefp,intx)/*③.参数fp的类型是FunType。*/{fp(x);/*④。执行通过fp的指针传入的函数。注意fp指向的函数有一个参数。*/voidMyFun1(intx)/*①.这是一个只有一个参数的函数,下面两个函数也是一样的。*/{printf("MyFun1:%d\n",x);}voidMyFun2(intx){printf("MyFun2:%d\n",x);}voidMyFun3(intx){printf("MyFun3:%d\n",x);}运行结果如下:可以看到CallMyFun函数的参数是一个指针。当函数指针有参数时,需要再增加一个参数来保存回调函数的参数值。同理,也可以使用带多个参数的函数指针。MCUIAP在MCUOTA中经常使用函数指针,代码如下:typedefvoid(*IapFun)(void);//定义函数指针IapFunJump_To_Application;//定义函数指针对象if(((*(__IOuint32_t*)appxaddr)&0x2FFE0000)==0x20000000)//检查地址是否有效{Jump_To_Application=(iapfun)*(__IOuint32_t*)(appxaddr+4);//用户代码区第二个字是程序startaddress(resetaddress)MSR_MSP(*(__IOuint32_t*)appxaddr);//初始化APP栈指针(用户代码区第一个字用于存放栈顶地址)Jump_To_Application();//跳转到app}这里直接把地址转换成函数指针,执行函数。appxaddr地址为新固件存储的起始地址,appxaddr+4所在位置为新固件中的Reset_Handler函数,相当于执行新固件中的Reset_Handler。