笔试是会遇到一些复杂指针,如:
13、定义一个函数指针,指向的函数有两个int形参并且返回一个函数指针,返回的指针指向一个有一个int形参且返回int的函数?
A、int (*(*F)(int, int))(int)
B、int (*F)(int, int)
C、int (*(*F)(int, int))
D、*(*F)(int, int)(int)
14、声明一个指向含有10个元素的数组的指针,其中每个元素是一个函数指针,该函数的返回值是int,参数是int*,正确的是()
A、(int *p[10])(int*);
B、int [10]*p(int *);
C、int (*(*p)[10])(int *);
D、int ((int *)[10])*p;
E、以上选项都不正确
这里介绍两篇讲解得不错的博客:
常见复杂指针声明的解析
原文地址:http://blog.youkuaiyun.com/lizhiguo0532/article/details/5778908
【
声明:1. 文章如有不妥的地方,请您指正,谢谢.
2.另外文中有些细节可能引用您的内容却未给出参考,请原谅我的疏忽,你的共享我不会忘记.
3. Email:lizhiguo0532@163.com 李枝果/lizgo
4. 转载请保留该部分信息
】
//两个原则
//右左法则:首先从最里面的圆括号看起,然后往右看,再往左看。每当遇到圆括号时,就应该掉转阅读方向。一旦解析完圆括号里面所有的东西,就跳出圆括号。重复这个过程直到整个声明解析完毕。
//坚持使用typedef来进行类型重定义,不确定优先级的地方可以多加括号。
1. int *p[N];
//这个就是int型指针数组,即N个int型指针所组成的数组
2. int (*p)[N];
//首先p是一个指针,基类型是具有N个int元素的数组,即数组指针
3. int (*p[M])[N];或者int (*(p[M]))[N];
//这是一个数组指针数组,怎么看呢?先看括号内的,*p[M],很显然这是一个数组(优先级[]高于*),什么数组呢?具有M个指针变量的数组。括号内的类型是指针,着我们知道了,跳出括号,int (指针)[N],
//是不是很眼熟?看2的形式,所以里面的指针不是一般的指针,而是具有N个整型数据的数组指针。
//如果现在我们要定义一个数组指针数组来访问二维数组a[5][4],该怎么定义呢?
//我们就和解析的过程反着来定义就可以了,看到这个名字,“数组指针数组”,从左往右看,先看到数组指针,那我们就先来定义数组指针,注意,将来是要访问a[5][4]的(a是一个具有5个元素的数组,这5个元
//素每个都是具有4个int数据的一维数组),将来我们的数组指针就是要指向这个一维数组的
//数组指针定义:int (*p)[4]; 再来定义指针数组,在这里前面的数据类型本来就已经是指针(数组指针)了,所以在 *pa[M]里就没必要加*了,可以直接定义成int (*p[M])[N];
//如果我利用typedef就简单明了多了:
//可以参考的形式有:
//a.
typedef int (*A)[N];
typedef A (B[M]);
B b;//等价于int (*(b[M]))[N];比较局限
//b.
typedef int (*A)[N];
typedef A (B);
B b[M];//等价于int (*(b[M]))[N];
//c.
typedef int (A)[N];
typedef A *(B[M]);
B b;//等价于int (*(b[M]))[N];比较局限
//d.
typedef int (A)[N];
typedef A *(B);
B b[M];//等价于int (*(b[M]))[N];
//e.
typedef int (*(A))[N];
A b[M];
//f.
typedef int A[N];
A *b[M];
//上面的声明中,()在有的地方是可以不加的
4. int (*func)(int *p);
//这是一个基本的函数指针定义方法,无法分解。(这里说明的是:函数名内容也是地址)
5. int (*func)(int *p, int (*f)(int*));
//用typedef分解:
typedef int (*FUNC)(int *);
int (*func)(int *p,FUNC f);
//典型的例子
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
//展开如下:
void (* signal(int signum, void (* handler)(int)))(int );
6. int (*func[5])(int *p);
// 这是一个函数指针数组,总的来说func是个数组,什么样的数组呢?原来里面的数组元素都是一个个函数指针。可以这样分解
typedef int (* FUNC)(int *p);
FUNC func[5];
//func这个数组的元素的类型是参数维int *,返回值为int 的函数指针
7. int (*(*func)[5])(int *p);
//这是一个函数指针数组指针,注意读法,前面六个字函数指针数组是修饰最后的指针,所以总提来说func是一个指针,什么样的指针呢?
//指向具有5个元素的数组,那这个数组的元素是什么类型呢?哦,原来是函数指针类型,什么类型的函数指针呢?参数int *,返回值 int。
//用typedef分解
typedef int (* (A))(int *p);
typedef A (B)[5];
typedef B *M
M func;
//或者
B *func;
8. int (*(*func)(int *p))[5];
//乍一看,我也看不出来它什么类型,不过可以分解嘛
typedef int (*(A))[5];//A是函数指针类型
A (* func)(int *p);
//这下该看出来是什么类型来吧,func是个函数指针,它参数很简单 int *,复杂就复杂在返回值,返回值的类型是A,A的类型就是一个数组指针,
//而且这个数组指针指向的是具有5个int数据的数组。
总结:
1.如果我们是去读别人的已经声明好的复杂类型,那么我们可以这样,用typedef来将其分解,分解的原则是:
从最外层的开始用typedef来定义,然后用定义好的类型再去一层一层得定义内部,知道遇见了被定义的标示符为止
2.如果我们知道需要声明一个什么东西了,比如前面的 “函数指针数组指针”,我们这样来声明:从左往右看,找到第一个修饰词“函数指针”,我们就定义一个函数指针
接下来遇到来“数组”,我们再用定义好的函数指针类型来定义一个数组。最后,我们在这个数组的类型上再定义一个指针就 可以了。
右左法则----复杂指针解析
原文地址:http://blog.sina.com.cn/s/blog_6461040f0100guwn.html
因为C语言所有复杂的指针声明,都是由各种声明嵌套构成的。如何解读复杂指针声明呢?右左法则是一个既著名又常用的方法。不过,右左法
则其实并不是C标准里面的内容,它是从C标准的声明规定中归纳出来的方法。C标准的声明规则,是用来解决如何创建声明的,而右左法则是用
来解决如何辩识一个声明的,两者可以说是相反的。右左法则的英文原文是这样说的:
The right-left rule: Start reading the declaration from the innermost parentheses, go right, and then go left. When you
parsed, jump out of it. Continue till the whole declaration has been parsed.
这段英文的翻译如下:
笔者要对这个法则进行一个小小的修正,应该是从未定义的标识符开始阅读,而不是从括号读起,之所以是未定义的标识符,是因为一个声明里面可能有多个标识符,但未定义的标识符只会有一个。
现在通过一些例子来讨论右左法则的应用,先从最简单的开始,逐步加深:
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元素的数组。
要注意有些复杂指针声明是非法的,例如:
int func(void) [5];
func是一个返回值为具有5个int元素的数组的函数。但C语言的函数返回值不能为数组,这是因为如果允许函数返回值为数组,那么接收这个数组的内容的东西,也必须是一个数组,但C语言的数组名是一个右值,它不能作为左值来接收另一个数组,因此函数返回值不能为数组。
int func[5](void);
func是一个具有5个元素的数组,这个数组的元素都是函数。这也是非法的,因为数组的元素除了类型必须一样外,每个元素所占用的内存空间也必须相同,显然函数是无法达到这个要求的,即使函数的类型一样,但函数所占用的空间通常是不相同的。
作为练习,下面列几个复杂指针声明给读者自己来解析。
int (*(*func)[5][6])[7][8];
int (*(*(*func)(int *))[5])(int *);
int (*(*func[7][8][9])(int*))[5];
分解,增强可读性,例如对于声明:
int (*(*func)(int *p))[5];
可以这样分解:
typedef
typedef PARA (*func)(int *);
这样就容易看得多了。
答案,同时给出用typedef的分解方法:
int (*(*func)[5][6])[7][8];
func是一个指向数组的指针,这类数组的元素是一个具有5X6个int元素的二维数组,而这个二维数组的元素又是一个二维数组。
typedef int (*PARA)[7][8];
typedef PARA (*func)[5][6];
int (*(*(*func)(int *))[5])(int *);
func是一个函数指针,这类函数的返回值是一个指向数组的指针,所指向数组的元素也是函数指针,指向的函数具有int*形参,返回值为int。
typedef int (*PARA1)(int*);
typedef PARA1 (*PARA2)[5];
typedef PARA2 (*func)(int*);
int (*(*func[7][8][9])(int*))[5];
func是一个数组,这个数组的元素是函数指针,这类函数具有int*的形参,返回值是指向数组的指针,所指向的数组的元素是具有5个int元素
的数组。
typedef int (*PARA1)[5];
typedef PARA1 (*PARA2)(int*);
typedef PARA2 func[7][8][9];