当前位置: 首页 > article >正文

【程序】C语言右左法则----复杂指针解析

因为C语言所有复杂的指针声明,都是由各种声明嵌套构成的。如何解读复杂指针声明呢?右左法则是一个既着名又常用的方法。不过,右左法则其实并不是C标准里面的内容,它是从C标准的声明规定中归纳出来的方法。C标准的声明规则,是用来解决如何创建声明的,而右左法则是用来解决如何辩识一个声明的,两者可以说是相反的。右左法则的英文的翻译如下:

右左法则:首先从最里面的圆括号看起,然后往右看,再往左看。每当遇到圆括号时,就应该掉转阅读方向。一旦解析完圆括号里面所有的东西,就跳出圆括号。重复这个过程直到整个声明解析完毕。

笔者要对这个法则进行一个小小的修正,应该是从未定义的标识符开始阅读,而不是从括号读起,之所以是未定义的标识符,是因为一个声明里面可能有多个标识符,但未定义的标识符只会有一个。

现在通过一些例子来讨论右左法则的应用,先从最简单的开始,逐步加深:

int(*func)(int*p);

首先找到那个未定义的标识符,就是func,它的外面有一对圆括号,而且左边是一个*号,这说明func是一个指针,然后跳出这个圆括号,先看右边,也是一个圆括号,这说明(*func)是一个函数,而func是一个指向这类函数的指针,就是一个函数指针,这类函数具有int*类型的形参,返回值类型是int。

int(*func)(int*p,int(*f)(int*));

func被一对括号包含,且左边有一个*号,说明func是一个指针,跳出括号,右边也有个括号,那么func是一个指向函数的指针,这类函数具有int*和int(*)(int*)这样的形参,返回值为int类型。再来看一看func的形参int(*f)(int*),类似前面的解释,f也是一个函数指针,指向的函数具有int*类型的形参,返回值为int。

int(*func[5])(int*p);

func右边是一个[]运算符,说明func是一个具有5个元素的数组,func的左边有一个*,说明func的元素是指针,要注意这里的*不是修饰func的,而是修饰func[5]的,原因是[]运算符优先级比*高,func先跟[]结合,因此*修饰的是func[5]。跳出这个括号,看右边,也是一对圆括号,说明func数组的元素是函数类型的指针,它所指向的函数具有int*类型的形参,返回值类型为int。

int(*(*func)[5])(int*p);

func被一个圆括号包含,左边又有一个*,那么func是一个指针,跳出括号,右边是一个[]运算符号,说明func是一个指向数组的指针,现在往左看,左边有一个*号,说明这个数组的元素是指针,再跳出括号,右边又有一个括号,说明这个数组的元素是指向函数的指针。总结一下,就是:func是一个指向数组的指针,这个数组的元素是函数指针,这些指针指向具有int*形参,返回值为int类型的函数。

int(*(*func)(int*p))[5];

func是一个函数指针,这类函数具有int*类型的形参,返回值是指向数组的指针,所指向的数组的元素是具有5个int元素的数组。

要注意有些复杂指针声明是非法的,例如:

intfunc(void)[5];

func是一个返回值为具有5个int元素的数组的函数。但C语言的函数返回值不能为数组,这是因为如果允许函数返回值为数组,那么接收这个数组的内容的东西,也必须是一个数组,但C语言的数组名是一个右值,它不能作为左值来接收另一个数组,因此函数返回值不能为数组。

intfunc[5](void);

func是一个具有5个元素的数组,这个数组的元素都是函数。这也是非法的,因为数组的元素除了类型必须一样外,每个元素所占用的内存空间也必须相同,显然函数是无法达到这个要求的,即使函数的类型一样,但函数所占用的空间通常是不相同的。

作为练习,下面列几个复杂指针声明给读者自己来解析。

int(*(*func)[5][6])[7][8];

int(*(*(*func)(int*))[5])(int*);

int(*(*func[7][8][9])(int*))[5];

实际当中,需要声明一个复杂指针时,如果把整个声明写成上面所示的形式,对程序可读性是一大损害。应该用typedef来对声明逐层分解,增强可读性,例如对于声明:

int(*(*func)(int*p))[5];

可以这样分解:

typedefint(*PARA)[5];

typedefPARA(*func)(int*);

这样就容易看得多了。

答案,同时给出用typedef的分解方法:

int(*(*func)[5][6])[7][8];

func是一个指向数组的指针,这类数组的元素是一个具有5X6个int元素的二维数组,而这个二维数组的元素又是一个二维数组。

typedefint(*PARA)[7][8];

typedefPARA(*func)[5][6];

int(*(*(*func)(int*))[5])(int*);

func是一个函数指针,这类函数的返回值是一个指向数组的指针,所指向数组的元素也是函数指针,指向的函数具有int*形参,返回值为int。

typedefint(*PARA1)(int*);

typedefPARA1(*PARA2)[5];

typedefPARA2(*func)(int*);

int(*(*func[7][8][9])(int*))[5];

func是一个数组,这个数组的元素是函数指针,这类函数具有int*的形参,返回值是指向数组的指针,所指向的数组的元素是具有5个int元素的数组。

typedefint(*PARA1)[5];

typedefPARA1(*PARA2)(int*);

typedefPARA2func[7][8][9];

 


http://www.kler.cn/a/455300.html

相关文章:

  • GTM023 W.H.Greub线性代数经典教材:Linear Algebra
  • 如何调用百度文心(Baidu Wenxin)和讯飞星火(iFlytek Spark)API
  • 《一文读懂卷积网络CNN:原理、模型与应用全解析》
  • IBatis和MyBatis在细节上的不同有哪些
  • python递归最多多少层
  • 【YOLOv3】源码(train.py)
  • Cascader 级联选择器一级单选二级多选
  • TCP off-path exploits(又一个弄巧成拙的例子)
  • PyAudio库基本知识详解——为自制PCM音频播放器做准备
  • 指针详解之 难点、易错点一次性彻底击碎!
  • vue3和springboot使用websocket通信
  • AI发展新态势:从技术突破到安全隐忧
  • MySql:复合查询
  • react中使用ResizeObserver来观察元素的size变化
  • 在线免费批量生成 Word 文档工具
  • Linux编程(清华大学出版社2019年1月第1版)第7章-进程间通信-课后作业
  • 信息安全管理:信息系统开发与维护安全控制要点与管理策略
  • 链原生 Web3 AI 网络 Chainbase 推出 AVS 主网, 拓展 EigenLayer AVS 场景
  • 【minicom】Linux串口调试工具 - minicom的安装及使用
  • Temporary failure resolving ‘security.ubuntu.com‘