以指向二维数组的指针为例,此指针应该是型如:(*p)[#],其中#为一常数。注意其中的括号不能省略,否则变成*p[#]表示的是#+1行的第一个元素。
更不要把**p当成指向二维数组的指针,**p是指向指针的指针。而指向二维数组的指针其实是指向一维指针数组的指针,而这个一维数组中存放着指向一维数据的指针。
举例说明:
#include <iostream>
using namespace std;
void main()
{
int a[2][3] = {{1, 2, 3}, {4, 5, 6}};
int (*p)[3] = a; //指向二维数组的指针是(*p)[3],而不是**p
cout<<p<<endl; //p中存放的是第一行第一个元素的地址
cout<<p + 1<<endl; //p+1中存放的是第二行第一个元素的地址
cout<<p[1]<<endl; //p[1]中存放的是第二行的第一个元素的地址,结合(***)处的代码来看
cout<<endl;
cout<<*p<<endl; //由这一行和下一行代码可知,*p存放二维数组的第一个元素的地址
cout<<*(p + 1)<<endl; //*(p + 1)存放的是第二行的第一个元素的地址
cout<<endl;
cout<<*a<<endl; //数组名也是指向第一个元素的地址
cout<<*(a + 1)<<endl;
cout<<endl;
cout<<*p[0]<<endl; //第一行的第一个元素,p先与右边的[0]结合组成p[0],再与*结合解指针,这样得到p[0]指向的值
cout<<*p[1]<<endl; //第二行的第一个元素
cout<<&(*p[1])<<endl; //第二行第一个元素的地址(***)
cout<<*p[2]<<endl; //此时越界
cout<<*p[3]<<endl; //越界
cout<<endl;
cout<<(*p)[0]<<endl; //第一行的第一个元素
cout<<(*p)[1]<<endl; //第一行的第二个元素
cout<<(*p)[2]<<endl; //第一行的第三个元素
cout<<(*p)[3]<<endl; //第二行的第一个元素
cout<<(*p)[4]<<endl; //第二行的第二个元素
cout<<(*p)[5]<<endl; //第二行的第三个元素
cout<<(*p)[6]<<endl; //此时越界
cout<<endl;
}
输出结果为:
由上例可以看出:
1. 指针和数组名都是存放的数组的第一个元素的地址
2. (*p)[1]与*p[1]比较:如果没有括号指针p将先与右边的括号结合组成p[1],然后再解指针得到的将是p[1]中存放的地址指向的值。p[1]中存放的是第二行的第一个元素的地址,所以*p[1]将得到4。而(*p)[#]将会按照顺序从第一行第一个元素开始逐个指到第二行最后一个元素,从(*p)[0]开始为第一个元素。
3. 定义指向二维数组的指针(*p)[3]中的3指的是二维数组的第二维是多少,即行数(因为二维数组是行优先的)。所以这里一定不能是其它任何值。正如在定义二维数组的同时如果进行初始化,能省略第一维不写但是不能省略第二维的大小,这也是两者之间的某种一致性。