爱美容
当前位置: 首页 美容百科

c语言指针函数使用方法(CC函数指针与指针函数)

时间:2023-07-06 作者: 小编 阅读量: 1 栏目名: 美容百科

关于指针,前面文章C语言指针详解有过介绍,这里主要讨论函数指针和指针函数。而指针变量保存的就是这个编号,也即内存地址。因此“函数指针”本身首先应是指针变量,只不过该指针变量指向函数。这正如用指针变量可指向整型变量、字符型、数组一样,这里是指向函数。函数指针的赋值函数指针和其他指针一样定义之后使用之前也是需要初始化。指针函数的调用在调用指针函数时,需要一个同类型的指针来接收其函数的返回值。

关于指针,前面文章C语言指针详解有过介绍,这里主要讨论函数指针和指针函数。

来自公众号:C语言与cpp编程

1 什么是指针?

定义:指针是程序数据在内存中的地址,而指针变量是用来保存这些地址的变量;

上面一个 4GB 的内存可以存放 2^32 字节的数据。左侧连续的十六进制编号就是内存地址,每个内存地址对应一个字节的内存空间。而指针变量保存的就是这个编号,也即内存地址。

指针的声明:

指针其实就是一个变量,指针的声明方式与一般的变量声明类似,如下:

int*p;//声明一个int类型的指针p,该指针指向一个int类型的对象char*p//声明一个char类型的指针p,该指针指向一个int类型的对象int*arr[10]//声明一个指针数组,该数组有10个元素,其中每个元素都是一个指向int类型对象的指针int(*arr)[10]//声明一个数组指针,该指针指向一个int类型的一维数组int**p;//声明一个指针p,该指针指向一个int类型的指针

声明一个指针变量并不会自动分配任何内存。在对指针进行间接访问之前,指针必须进行初始化:或是使他指向现有的内存,或者给他动态分配内存,否则我们并不知道指针指向哪儿,这个问题需要特别关注。

2 什么是函数指针?

函数指针定义:函数指针是指向函数的指针变量。 因此“函数指针”本身首先应是指针变量,只不过该指针变量指向函数。这正如用指针变量可指向整型变量、字符型、数组一样,这里是指向函数。

其通用表达式为:类型说明符 (*函数名) (参数)

int(*fun)(intx)//函数指针的定义int(*fun)(intx,inty)//函数指针的定义

函数指针在PC软件开发中使用较少,在嵌入式行业使用较多,但是无论是PC软件还是嵌入式软件,理解函数指针的定义和使用,对于理解程序设计都是很有好处的。

函数指针的赋值

函数指针和其他指针一样定义之后使用之前也是需要初始化。

函数指针有两个用途:调用函数和做函数的参数

int(*fun)(intx,inty)//函数指针的定义fun=&Function//函数指针的赋值方式1fun=Function//函数指针的赋值方式2x=(*fun)()//函数指针的调用方式1x=fun()//函数指针的调用方式2

函数赋值的时候取地址运算符&不是必需的,因为一个函数标识符就表示了它的地址,并且赋值的时候函数不需要带圆括号;

如果是函数调用,还必须包含一个圆括号括起来的参数表。

函数指针的用法

我们使用指针的时候,需要通过钥匙 * 来取其指向的内存里面的值,函数指针使用也如此。通过用(*pf)取出存在这个地址上的函数,然后调用它。

char*fun(char*p1,char*p2){inti=0;i=strcmp(p1,p2);if(0==i){returnp1;}else{returnp2;}}intmain(){char*(*pf)(char*p1,char*p2);pf=&fun;(*pf)("aa","bb");return0;}

这里需要注意到是,在Visual C6.0里,给函数指针赋值时,可以用&fun或直接用函数名fun。这是因为函数名被编译之后其实就是一个地址,所以这里两种用法没有本质的差别。

用法延申

当我们不满足于函数指针上面如此简单的用法时,这时候需要一个高级用法来扩展我们对于函数指针的认知边界。

感兴趣的同学可以看看下面这个用法,并尝试理解该表达式是如何使用的函数指针。

(*(void(*)())0)();//出自《CTrapandPitfalls》这本经典的书

答案如下: ``

  • 第一步:通过void(*) (),可以明白这是一个函数指针类型。这个函数没有参数,没有返回值。
  • 第二步:通过(void(*) ())0,可以明白这是将0强制转换为函数指针类型,0是一个地址,也就是说一个函数存在首地址为0的一段区域内。
  • 第三步:通过(*(void(*) ())0),可以明白这是取0地址开始的一段内存里面的内容。
  • 第四步:最终理解(*(void(*) ())0)(),这是函数调用。
让程序跳转到绝对地址为0x0113F90C

方法一:

  • 将0x0113F90C地址强制转换为函数指针类型,即: (void (*)())0x0113F90C
  • 然后调用:((void (*)())0x0113F90C)()

方法二:

typedef(void(*)())VoidFuncPtr;((VoidFuncPtr)0x0113F90C)();

面试题:指出程序的错误

#include<stdio.h>voidmain(void){intmax(x,y);int*p=max;inta,b,c,d;scanf("%d%d%d",a,b,c);d=p(p(a,b),c);printf("d:%d\n",d);return;}intmax(inta,inty){return(x>y?x:y);}

答案

  • int max(x ,y);函数声明错误,改为:int max(int x,int y);

解析:max函数声明只是写出了函数的形参的名称,这对参数的类型来说是毫无意义的,编译器会把x和y当做数据类型来看,编译时会出错,max的调用肯定也会出错。

  • int *p=max;指针定义错误,改为:int (*p)(int ,int)=max;

解析:函数的指针是不能直接赋值给int型指针.

  • scanf("%d %d %d",a,b,c);库函数使用错误,改为scanf("%d %d%d",&a,&b,&c);

解析:库函数使用错误,第二部分应该是接收数据的地址,这里却写成了变量。

  • d=p(p(a,b),c);函数指针调用函数错误,改为d=(*p)((*p)(a,b),c); `

解析:用函数指针调用函数的格式如下:(【*】【函数指针名称】)(【参数列表】);不能直接用函数指针加上参数就直接调用

3 什么是指针函数?

指针函数定义:指针函数的落脚点是一个函数,这个函数的返回值是一个指针,与普通函数int function(int,int)类似,只是返回的数据类型不一样而已。

_type_*function(int,int)//返回的是指针地址intfunction(int,int)//返回的是int型数据。

int*fun(intx)//指针函数的定义int*fun(intx,inty)//指针函数的定义int*fun(intx,inty)//指针函数的定义

以上三种写法均正确,但是*靠近返回值一点更容易理解。

指针函数的调用

在调用指针函数时,需要一个同类型的指针来接收其函数的返回值。

typedefstruct_Data{inta;intb;}Data;//指针函数Data*f(inta,intb){Data*data=newData;data->a=a;data->b=b;returndata;}intmain(intargc,char*argv[]){QApplicationa(argc,argv);//调用指针函数Data*myData=f(4,5);qDebug()<<"f(4,5)="<<myData->a<<myData->b;returna.exec();}

不过也可以将其返回值定义为 void* 类型,在调用的时候强制转换返回值为自己想要的类型。

其输出结果是一样的,不过不建议这么使用,因为强制转换可能会带来风险。返回类型可以是任何基本类型和复合类型。返回指针的函数的用途十分广泛。

事实上,每一个函数,即使它不带有返回某种类型的指针,它本身都有一个入口地址,该地址相当于一个指针。

比如函数返回一个整型值,实际上也相当于返回一个指针变量的值,不过这时的变量是函数本身而已,而整个函数相当于一个“变量”。

4 函数指针和指针函数的区别

通过以上的介绍,小伙伴应该都能理解二者的定义。那么简单的总结下二者的区别:

1. 定义不同
  • 指针函数本质是一个函数,其返回值为指针。
  • 函数指针本质是一个指针,其指向一个函数。
2. 写法不同
  • 指针函数:int* fun(int x,int y);
  • 函数指针:int (*fun)(int x,int y);

可以简单粗暴的理解为,指针函数的*是属于数据类型的,而函数指针的星号是属于函数名的。

再简单一点,可以这样辨别两者:函数名带括号的就是函数指针,否则就是指针函数。

3. 用法不同

上面函数指针和指针函数的用法都有,但是函数指针的用法会更多,相对而言难度也更大,例如函数指针与回调函数,如果是C非静态成员函数指针,其用法也会有一些区别,感兴趣的同学可以关注后续推文或自行查阅相关书籍。

总而言之,这两个东西很容易搞混淆,一定要深入理解其两者定义和区别,避免犯错。

    推荐阅读
  • 怎么样让眼睛变大的最有效的方法(5种方法让你的眼睛变大)

    使用时先轻刷一层睫毛膏,趁睫毛膏尚未干掉时,将增长纤维的刷头转出,并将刷头上的白色细致纤维轻轻以滚动方式附着每根睫毛的尖端部位。再重复刷上黑头睫毛膏,电眼效果max。

  • 双减带给老师的挑战和机遇(双减之后教师面临的)

    7月24日,中共中央办公厅、国务院办公厅印发了《关于进一步减轻义务教育阶段学生作业负担和校外培训负担的意见》。面对教师陡然增加的负担,教育部相关负责人回应,将继续督促指导各地将教师减负工作同优化教师资源配置、深化教育教学改革等有机结合起来,健全教师减负长效机制,推动教师减负工作取得实效。“双减”政策明确提出,要构建教育良好生态,有效缓解家长焦虑情绪,促进学生全面发展、健康成长。

  • 我的世界橡胶甘蔗怎么杂交 我的世界粘性甘蔗种子

    杂交前需要合成作物架,用4个木棍合成,摆放成左右两列,合成2个作物架,由于杂交的几率比较低,所以需要准备多点作物架。拿着作物架在,每两个种了甘蔗的耕地的中间,放上两个作物架,作物架成十字交叉,代表此时在进行杂交。进行一段长时间的等待,等待甘蔗长大,等待杂交成功,注意杂交的地方很容易长杂草,如果长了杂草请尽快打掉,否则整个耕地都会蔓延杂草,需要重新杂交。

  • 娃哈哈新媒体营销策划(第13届娃哈哈营销策划大赛重磅来袭)

    为了丰富大学生的课余生活,引导和培养大学生创新精神和实践能力,4月23日18时30分,第十三届娃哈哈全国大学生营销策划大赛启动仪式于南宁职业技术学院大礼堂顺利举行。娃哈哈营销大赛为大学生提供了一个广阔的实践平台,推动教育与实践相结合,使同学们的创新意识得到激发。在此预祝娃哈哈营销策划大赛取得圆满成功,也祝本次参赛的团队都能够在比赛中取得佳绩!

  • 狮鹫怎么驯服(方舟生存进化手游狮鹫驯服技巧攻略)

    接下来我们就一起去研究一下吧!狮鹫怎么驯服方舟生存进化中狮鹫是高傲的守护兽,想要驯服狮鹫并不容易,必须获得狮鹫的尊重,这并不算容易的事,下面就来介绍一下怎么驯服狮鹫的方法吧。第一种方法:人物等级85级以上,并且不是可以获得全部尊重的!比如85级的,可能只能获取低等级狮鹫的尊重!

  • tabata间歇性训练的方法(什么是Tabata锻炼)

    各种研究得出结论,Tabata锻炼对健康有很多好处。有时您可能会达到最大强度,这可能会因肌肉松懈而导致受伤每周最多进行3-4次Tabata训练。Tabata锻炼以多种方式改善健康。此外,心脏病患者在开始Tabata锻炼之前还应听取医生的建议。在没有科学证据的情况下,对原始Tabata版本的修改可能弊大于利。人们可能会选择Tabata只是为了减肥,这不是它的实际用途。与传统HIIT相比,Tabata的强度水平更高,恢复时间更短。

  • s10和s9有什么区别(s10和s9有什么区别瑞思迈)

    vivoS9电池容量4000mAh,配置33W闪充。vivo官方宣布vivoS10系列于2021年7月15日正式发布,该手机代言人有Lisa、蔡徐坤、刘昊然。2021年7月15日,vivo召开了S10系列发布会,会上发布了新一代自拍旗舰vivoS10系列,其vivoS10系列依然采用了前置4400万像素AF双摄设计,仍然支持105度超广角,还有前置微缝式双柔光灯。

  • 专业版微博怎么设置(其实很简单)

    接下来我们就一起去了解一下吧!专业版微博怎么设置需要认证过才能成为专业版。专业版微博是为企业和机构定制的微博。新浪微博企业版是我们为企业、机构用户量身打造的服务平台。它具有更丰富的个性化页面展示功能设置,更精准的数据分析服务,以及更高效的沟通管理后台。我们期待新浪微博企业版能够帮助企业更便捷地与目标用户进行互动沟通,提升营销效果转化,挖掘更多商业机会。

  • 变速箱油到底多久换一次呢(变速箱油多久更换一次)

    如果需要更换变速箱油,查看用户的保养手册上如果有明确的更换周期,按照规定换油。如果变速箱油是终身免维护的,也一样要引起重视,终身免维护并不意味着变速箱油一直不用换。其实变速箱油不像机油那么黑,相比于机油甚至更为干净一点。所以车主千万不要忽略变速箱油,如果过长时间不更换,也会对变速箱造成一定的损伤,而且一些汽车的变速箱比发动机还要昂贵,修一次可能得要好几万元。

  • 恐惧症会遗传吗 幽闭恐惧症会遗传吗

    恐惧症是发病率非常高的一种心理疾病,而有许多患者并没有得到有效的治疗。导致恐惧症的因素恐惧症是各种因素的共同作用。恐惧症的典型症状是恐怖发作,并伴有强烈的生理反应。尽管患者知道这种恐惧是不合理的,但是没法控制。研究表明,在100名患者中40名患者可以彻底治疗,基本上没有什么后遗症。所以一定要及早治疗,效果好,造成的危害也小。