编程是两队人马在竞争:软件工程师努力设计出最大最好的连白痴都会使用的程序;而宇宙在拼命制造最大最好的白痴。到目前为止,宇宙是胜利者。
——Rick Cook
欢迎回来!准备好面对该系列中最精彩的一步了吗?我想你既然已经点开了,就无须再回答这个问题了。来看看我们今天的主角:
函数指针
这可谓是整个C语言中最令人头疼、最难以捉摸——同时也是最令人激动和最为锋利的武器了:顾名思义,函数指针就是创建一个指向某个地址的指针,唯一不同的是,这个地址是代码段中的。
是不是有点糊涂了?别急,让我们先回顾一下指针最基本的一个重点:
指针标识符(*)是修饰变量名,而非类型的
这句话在我们接下来的讨论当中将是你保持思想清明的最大依仗,记住了吗?让我们继续吧:
类型声明
要说函数指针和普通指针最大的差异在哪里,那首先要当属声明的方式不同了,当普通指针长成这样的时候
int a=0,*intPtr;
printf("%d",*intPtr);
函数指针却长成这样
void func(int a,int b);
void (*funPtr)(int,int);
开始犯糊涂了?别急,让我们慢慢剖析
首先,这个指针的定义大概可以分成三个部分:参数类型、函数名和参数列表,是不很眼熟?没错,事实上这个函数指针和函数的唯一区别就是指针标识符(*),它修饰在函数名的时候,就让它变成了一个指向类型和参数列表与指针的定义相同的函数(其实不一样也行,但这块更深入的内容这里篇幅有限,有兴趣的小伙伴可以去搜一下C语言的变长函数:printf()和scanf()的实现原理)。
好的,那么我们现在有一个函数指针了,该怎么用呢?
函数的本质
函数的本质嘛,指针,就是一个指向代码段的指针。这个套路是不是有点眼熟?没错,就像数组一样,函数的指针也是交给编译器来搞定的。现在做个竞速题,开动你的小脑瓜,想想本质是数组的指针可以被怎么调用来着?
时间到!太晚了,但是恭喜你,你刚刚在世界上第一个写在书里的竞速题目里失败了。
但是别灰心,它其实并不难搞,你只需要像类似这样去赋值:
funPtr = func;
or
funPtr = &func;
然后这样去用
funPtr(a,b);
or
(*funPtr)(a,b);
看起来是不是很简单?其实函数指针就是这么简单,你也可以试试用(*func)的方式直接调用,看看结果会不会出人意料?
好好好,我说我说,有话好说,我这就给你讲一开头的那个指向指向指针函数的函数指针数组的指针是什么,你先把刀放下,有话好说…
(((指针函数)指针)数组)指针
哈,其实看到这个标题你大概就能明白究竟是怎样的一个定义格式了,不过为了我的项上人头着想,还是给出一个范例吧:
(((void*(int))*)) array[];
(((void*(int))*)) *ptr = array;
相信任何一个看到这种式子的人都会打从心眼里不寒而栗——我说真的,这简直就是C程序员的降压药,可以帮助他们快速归零血压。
但是,同样也有更好的解决办法可以处理这种疑难杂症,我们只需要…
typedef void* (*FuncPtr)(int);
FuncPtr array[];
FuncPtr *ptr = array;
令人吃惊的简洁!typedef在这方面做出的贡献简直应该称之为无与伦比的美丽,我强烈推荐你在需要的时候试试利用typedef定义函数指针,你会爱上他的(并且同时甩开烦人的括号)。
当然,最好还是不要盲目利用函数指针,这比什么都强。
后记
其实这三篇文章一共花费了我差不多一下午+一上午的时间,因此难免有许多疏漏,也欢迎的大家加我的QQ1377266215进行讨论,共同进步。
在这里还要特别感谢bit哥,没有他的文章,就没有这篇博客(散文?)的面世,他写的技术文章也相当不错,有需求的小伙伴可以去看一看。他的博客在这
这里有个人推荐的几本C/C++好书,CSDN价格还是蛮良心的,一个C/C++程序员最好都备上一本↓
转载:https://blog.csdn.net/u013506650/article/details/115346008