对应的视屏链接:鲍松山的个人空间_哔哩哔哩_bilibili
目录
上一节讲述了数组指针、指针数组、函数指针、指针函数,其内容是本章理解复杂指针的重要基础,首先看一个声明:int * (* (*fun) (int *)) [10]这是一个可能会让初学者感到头晕目眩,感到恐惧的函数指针的声明, 在熟练掌握 C/C++的声明语法之前,不学习一定的规则,想理解好这类复杂声明往往是比较困难的
1、右左法则
C/C++所有复杂的声明结构,都是由各种声明的嵌套构成的,如何理解复杂指针声明,右左法则是一个很著名,很有效的方法
右左法则——首先从未定义的标识符开始看起,然后往右看,再往左看,每当遇到圆括号时,就应该调转阅读方向,一旦解析完圆括号里面的所有东西,就跳出圆括号,重复这个过程直到整个声明解析完毕。
所谓复杂指针,个人认为,无外乎就是指针跟数组、函数的结合,外加括号多,星号多,从而导致一个指针的类型变得复杂多样化而已,不过只要掌握了方法,只要是能被定义出来的指针,无论怎样复杂都可以被解析。
2、复杂指针
int *(*(*func)(int *))[10];
int (*func)(int *, int (*)(int *));
int (*func[5])(int *);
int (*(*func)[5])(int *);
int (*(*func)(int *)) [5];
(*(void(*)())0)();
void(*set_new_handler(void(*f)()))();
3、解析
复杂指针 1:
int * (* (*func) (int *)) [10]
解析:
首先 func 是一个指针,该指针指向一个函数,函数的特征是具有一个整形指针参数和一个指针的返回值,该指针指向的是数组,数组具有十个元素,其中每个元素都是整形指针。
复杂指针 2:
int (*func)(int *, int (*)(int *));
解析:
首先 func 是一个指针,该指针指向一个函数,函数的特征是具有两个参数和一个返
回值,其参数一个是整形指针参数,另一个是函数指针的参数,函数返回值为整形值。
复杂指针 3:
int (*func[5])(int *);
解析:
首先 func 是一个数组,数组具有五个元素,其中每个元素都是一个指针,该指针指向
函数,函数的特征是具有一个整形指针的参数和一个整形的返回值
复杂指针 4:
int (*(*func)[5])(int *);
解析:
首先 func 是一个指针,该指针指向数组,数组具有五个元素,每个元素都是指针,指
针指向函数,函数特征为一个整形指针参数和一个整形返回值
复杂指针 5:
int (*(*func)(int *)) [5];
解析:
首先 func 是一个指针,指针指向函数,函数特征为一个整形指针参数和一个指针的返
回值,其返回值指针指向的是具有五个整形数据的数组
复杂指针 6: (备注:以下内容摘自 C 陷阱与缺陷)
编写一个独立运行于某种微处理器上的 C 程序,当计算机启动时,硬件将调用首地址为 0 位置的子例程,于是最后得出语句:
(*(void(*)())0)()
这个表达式考的非常火,很多公司的面试官都会直接写出这个表达式,让其进行解析。当时确实难倒了不少人,不过,在现在看来,这个问题已经不难求解了。
那么如何解析这个语句了?首先假如我们已经知道如何声明一个给定类型的变量,那么该类型的类型转换就很容易得到:只需要把声明中的变量名和声明末尾的分号去掉,再将剩余的部分用一个括号整个“封装”起来即可。例如:
int (*pfun)();
表示声明 pfun 是一个指向返回值为整形类型的函数指针,因此,去掉变量名和结尾分号,利用括号括起来就会形成该类型的类型转换,例如:
(int (*) ())
这表示了一个“指向返回值为整形类型的函数的指针”的类型转化符。假如给该类型一个变量名,例如:
(int (*) ()) fun;
这就说明 fun 被强制转化为了(int (*) ())这样的函数指针类型。
拥有了以上预备知识,我们现在分两步来分析表达式(*(void(*)())0)()。
第一步: (void(*)())0 这部分内容表示了 0 被强制转换为了 void(*)()这种类型的函数指针,假如把(void(*)())0 形象想象为 pfun,则第二步就好解释了
第二步:0 被强制转换之后,就形象认为(*pfun)(),发现,由于 pfun 是函数指针,实际上这是在调用函数指针 pfun 所指的函数。
因此这个表达式的类型和作用就分析清楚了,同时也达到了对当计算机启动时,硬件调用首地址为 0 位置的子例程的概念。
复杂类型 7:
首先void(*set_new_handler(void(*f)()))()不是指针,而是一个函数,大多数人会误解为是一个函数指针。
set_new_handler是函数名,参数为void(*f)()函数指针,返回值也是一个函数指针,指向无参无返回值的函数
4、简化复杂指针定义
简化定义的关键在于:typedef 类型重定义
例如:
-
简化 void(*set_new_handler(void(*f)()))()
typedef void(*pFun)();
pFun set_new_handler(pFun);
-
简化 int (*(*func)[5])(int *)
typedef int(*pFun)(int*);
pFun(*func)[5];
4、总结
其实复杂指针的困难在于指针与函数和数组的结合,只要我们能够分清其中的关键,另加右左法则,我想,针对这样的复杂指针就能轻松的解析。