右左法则解决复杂声明

简介: Author:bakari       Date: 2012.8.27 现在很多IT公司的面试题都或多或少会有复杂声明的题,有一点C基础的人或许能够瞎搬乱套做对,但这样你肯定不爽,一方面显得不专业,有点自欺欺人的感觉,另一方面如果遇到更加复杂的声明就彻底傻了,本篇主要就一些复杂的声明介绍一种方法,这个有些书上也有介绍,比如《C专家编程》。

Author:bakari       Date: 2012.8.27

现在很多IT公司的面试题都或多或少会有复杂声明的题,有一点C基础的人或许能够瞎搬乱套做对,但这样你肯定不爽,一方面显得不专业,有点自欺欺人的感觉,另一方面如果遇到更加复杂的声明就彻底傻了,本篇主要就一些复杂的声明介绍一种方法,这个有些书上也有介绍,比如《C专家编程》。个人觉得这个没有必要深究,只做了解即可,很多时候编程都很难用到,不过这也是大神和一般程序员的区别。

右左法则不是C标准里面的内容,它是从C标准的声明规定中归纳出来的方法。C标准的声明规则,是用来解决如何创建声明的,而右左法则是用来解决如何辩识一个声明的。

究竟右左法则的规律是什么呢?顾名思义,从声明的右边看到左边,下面是左右法则的专业解释:

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

下面通过10个例子来说明,由易到难,慢慢加深。

 

一、例子

(1)int (*func)(int *p);

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

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

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

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

(6)int func(void) [5]; //错误

(7)int func[5](void); //错误

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

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

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

可以自己先看,然后在看后面的答案:

 

二、 题目练习:
1、 D1ouble (*(*(*fp3)())[10])(), 采用右左法则对此表达式进行分析说明。
2、 int func(void) [5],采用右左法则对此表达式进行分析说明。
3、 int * (* (*fp1) (int) ) [10],采用右左法则对此表达式进行分析说明。

 

例子答案

(1)int (*func)(int *p);

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

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

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

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

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

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

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

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

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

(6)int func(void) [5];

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

(7)int func[5](void);

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

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

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

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

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

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

typedef int (*PARA1)(int*);
typedef PARA1 (*PARA2)[5];
typedef PARA2 (*func)(int*);

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

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

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

【小结】实际当中,需要声明一个复杂指针时,如果把整个声明写成上面所示的形式,对程序可读性是一大损害。应该用typedef来对声明逐层分解,增强可读性。例子(8)(9)(10)给出了typedef分解。另外,函数不能声明返回一个函数类型。

 

练习答案:

1、 定义一个指针指向一个函数,函数返回值 为一个指针,指向有10个元素组成的数组,数组里存的是一个指针,指向一个函数,函数返回值为double型。
2、 Func是一个参数类型为空,返回值为具有5个int型的数组的函数。函数的返回值不能为数组,数组只能作为右值,所以此函数非法。
3、 定义一个指针,指向一个函数,函数参数类型为int型,返回值为一个指针,指向10个元素组成的int型的指针数组。

参考之处:http://www.cnblogs.com/stli/archive/2010/03/04/1678357.html

目录
相关文章
|
搜索推荐 Java 应用服务中间件
【Maven】IDEA部署配置Maven项目教程,IDEA配置Tomcat(2019.3.3)(2023.1.3)
当涉及到软件开发和项目管理时,使用一个可靠的构建工具是非常重要的。Maven是一个广泛使用的构建工具,它为Java项目提供了一种简化的构建过程和依赖管理。 在本文中,我们将探讨如何部署Maven并开始使用它来构建您的项目。我们将介绍所需的步骤,并向您提供一些有用的提示和建议。
【Maven】IDEA部署配置Maven项目教程,IDEA配置Tomcat(2019.3.3)(2023.1.3)
|
SQL 安全 数据库
掌握SQL:数据库操作与查询的精髓
一、引言 在数据驱动的时代,数据库是任何组织或项目不可或缺的一部分
|
Java 测试技术 开发者
Java线程池ThreadPoolExcutor源码解读详解09-4种拒绝策略
本文介绍了线程池的四种拒绝策略:AbortPolicy、DiscardPolicy、DiscardOldestPolicy和CallerRunsPolicy,并通过代码示例展示了它们在任务过多时的不同处理方式。AbortPolicy会抛出异常并停止主线程;DiscardPolicy会默默丢弃新任务;DiscardOldestPolicy会抛弃队列中最旧的任务来接纳新任务;而CallerRunsPolicy则是由调用者线程执行被拒绝的任务,以减缓新任务的提交速度。这四种策略适用于不同的场景,开发者可以根据需求选择合适的策略。
1651 5
|
DataWorks NoSQL 关系型数据库
DataWorks操作报错合集之在使用 DataWorks 进行 MongoDB 同步时遇到了连通性测试失败,实例配置和 MongoDB 白名单配置均正确,且同 VPC 下 MySQL 可以成功连接并同步,但 MongoDB 却无法完成同样的操作如何解决
DataWorks是阿里云提供的一站式大数据开发与治理平台,支持数据集成、数据开发、数据服务、数据质量管理、数据安全管理等全流程数据处理。在使用DataWorks过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
289 1
|
前端开发 API
理解 React 18 中的 useId Hooks
理解 React 18 中的 useId Hooks
403 0
|
存储 云安全 弹性计算
阿里云ace考试试题以及关于阿里云ace的相关问题解答
阿里云ace认证对于个人来说可以证明你在技术领域的专业度,可以解决实际问题,获得更多阿里云的就业机会,对于企业来说通过云认证培养专业人才,提高公司云技术能力,而获得这个认证需要通过阿里云ace考试,接下来由认证大使为我们详细介绍阿里云ace考试试题。
588 1
阿里云ace考试试题以及关于阿里云ace的相关问题解答
|
JSON 算法 关系型数据库
MySQL 8.0.32如期而至
MySQL 8.0版本计划 MySQL 8.0开始采用快速迭代开发模式,基本上是每隔3个月就发布一个新的小版本。去年1月18日(2022.1.18)发布MySQL 8.0.28,今年1月17日发布MySQL 8.0.32,再看看其他几个版本的时间,还真是贼守时啊。
589 0
|
消息中间件 缓存 网络协议
【Spring常见错误】Rabbitmq 常见问题
rabbitmq是实现了高级消息队列协议(AMQP)的开源消息代理软件(亦称面向消息的中间件)。在安装使用过程中难免会遇到一些问题,这里将介绍几种常见问题以及解决方案提供参考。
1064 0

热门文章

最新文章