四、复杂指针解析


对应的视屏链接:鲍松山的个人空间_哔哩哔哩_bilibili


目录

1、右左法则

2、复杂指针

3、解析

4、简化复杂指针定义

4、总结


 

上一节讲述了数组指针、指针数组、函数指针、指针函数,其内容是本章理解复杂指针的重要基础,首先看一个声明: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、总结

其实复杂指针的困难在于指针与函数和数组的结合,只要我们能够分清其中的关键,另加右左法则,我想,针对这样的复杂指针就能轻松的解析。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值