指针为C/C++提供了高效的操作,但指针也有很多恼人之处,稍稍不注意就可能出现大问题了,当然,本文不讨论那些裸指针之类的后续问题,我们需要先了解的应该是指针的声明!试想,如果连声明都无法看懂,又何谈使用呢?
可能有人会说指针的声明这么简单,怎么可能看不懂。那我们来看一个例子:
int (*(*x)[10]) ();
看完它,不知各位是否还能继续说简单呢?下面我们就从基本的声明开始,一步一步理解这个复杂的指针声明究竟是什么。先从一个最简单的例子开始:
int *p;
一个最简单的int型指针,但我更倾向于称呼它指向int型变量的指针,如此称呼并不是刻意复杂化,而是它将对我们理解复杂指针有很大作用!再看一个例子:
int (*p)[10];
相信这个形式很多人已经非常熟悉了,在编写代码时使用二维数组会用到,但又有不少人会将它与 int *p[10] 相混淆,我们就从这个例子来介绍复杂指针的阅读!
首先,我们需要了解运算符的优先级:[] > () > *。在 int (*p)[10] 中,我们知道括号可以改变运算顺序,使得*p被先作用,则我们将它理解为p是1个指针,括号内运算完毕后,p就遇到了[]下标访问运算符,此时我们将它理解为p是1个数组。综上,我们是否应该将 int (*p)[10] 理解为包含10个指针的数组呢?这样我们就错了,还记得前文最简单的指针的理解么,对于此处,括号用于改变运算顺序,使得 * 用于强调p是1个指针,指针总要有指向吧!所以括号内运算完毕后遇到了[],好了,指向就有了。p是1个指向含有10个元素的数组的指针,最后,再来看基本类型int,我们就能得到完整的理解了:p是1个指向含有10个int型元素的数组的指针!
了解了这种阅读的方法,我们来解读一个例子试试身手:
int (*(*p)())[10];
从最内层括号开始,p是1个指针,然后,p是1个指向形参列表为空的函数的指针,这里就有一个我们需要注意的问题了,因为p是1个函数指针,我们知道,函数三要素:返回值,形参列表,函数体。对于声明来说,函数体是不必介绍的,但返回值和形参列表必须提出来。形参列表已经提过了,所以我们需要将剩下的运算统统视为返回值部分,我们了解这种用法
int (*x)[10],所以接下来我们就得到了返回值部分。综上,p就是1个指向返回值为int (*)[10]类型,形参列表为空的函数指针。
说了这么多,一定还有人对开头的例子感到好奇吧。它是什么呢?我们接下来再说道说道:(*x)[10]表明x是1个指向含有10个元素的数组的指针,然后遇到 * ,x即是1个指向含有10个指针元素的数组的指针,括号内运算结束,遇到(),x即是1个指向含有10个形参列表为空的函数指针的数组的指针,最后看返回值,我们就得到了最终结果:x是1个指向含有10个形参列表为空,返回值为int型的函数指针的数组的指针!
很绕对吧,不过仔细思考一番,理解了它,复杂声明也就像纸老虎一般不足为惧了!