一:前言

数组指针和指针数组是两个很容易让初学者感到模糊的概念,同时也是重点,所以希望读者能耐心阅读,仔细理解。

那么,什么是数组指针,什么又是指针数组呢?

int(*p)[2];//数组指针
int* p[2];//指针数组


在继续分析两者的区别前,需要读者了解3个问题:

1.二维数组是特殊的一维数组。

int a[2][2];
for (int i = 0; i < 2; i++)
for (int j = 0; j < 2; j++)
cout << &a[i][j] << endl;

我们发现输出的地址是连续的,很简单,不作解释。

2.数组地址。

int a[2];
int aa[2][2];

监视下类型图为:

数组指针与指针数组_数组


a是一维数组的数组名,值是一个地址,大小等于首元素地址,注意a不是变量,a[ 0 ]和a[ 1 ]才是变量,也就是不可以有a++之类的操作,类型是int[ 2 ](很多人认为a是指针类型int*,严格来说,不对,关于这点在下面会讲)。

&a是一维数组的数组地址,值是连续两个int元素的地址,只不过大小也等于首元素大小,类型是int[ 2 ]*。

aa是二维数组的数组名,值是一个地址,大小等于首元素地址,同样aa不是变量,类型是int[ 2 ][ 2 ]。

&aa是二维数组的数组地址,也就是连续四个int元素的地址,大小也是等于首元素地址,类型是int[ 2 ][ 2 ]*。

aa[ 0 ]是二维数组的第一行小数组的数组名,这里可以看做是a,类型和a是一样的。

&aa[ 0 ]是二维数组的第一行小数组的数组地址,也就是aa[ 0 ][ 0 ]和aa[ 0 ][ 1 ]的地址。

3.数组类型可以转化为指针类型。

int a[2];
int *p;
p = a;

int aa[2][2];
int(*pp)[2];
pp = aa;

在VS调试下,监视变量图为:

数组指针与指针数组_指针_02


我们知道,运算符=成立的前提是左右类型相同或者右类型可以转化为左类型。

在上图,a和p的类型是不同的,但是a=p却是成立的,同样的,aa=pp也是成立的。这是因为array type 可以转化为pointer type。即int[ ]转化为int*,int[ ][ ]转化为int[ ]*。如何使一个数组名退化成指针呢?只需对其进行数值计算即可,例如,a+0,aa+0。(其中a[0]等价*(a+0),aa[0]等价*(aa+0))

这也就解释了上面我所说的,a不是int*类型,只是可以转化而已,可以转化并不代表a就是int*类型的。打个比方,int和short可以转化,但是int不是short,只是可以转化而已。a的类型就是int[ 2 ],描述为a是一个数组,由两个int组成。


二:数组指针
int a[2];
int aa[2][2];
int(*p)[2];

p = a;//error
p = &a;//right

p = aa;//right
p = aa[0];//error
p= &aa[0];//right

int bb[2][3];
p = bb;//error

p是一个数组指针,类型是int[2] * ,含义是指向一个连续两个int元素的地址,也就是数组地址,数组地址在上面讲过,就是连续元素的地址,值为第一个元素地址。
p = a是错误的,因为a的类型是int[2],p的类型是int[2] * 。
p = &a是正确的,因为&a是数组地址。p = aa是正确的,因为array type 可以转换为pointer type。
p = aa[0]是错误的,因为aa[0]的类型是int[2],和a的类型一样。
p = &aa[0]是正确的,这个和p = &a是一样的道理。
p = bb是错误的,因为p是指向连续两个元素的地址,而bb是3个,无法转化。

关于数组指针的应用,应该就是传递参数的时候了,看下面的代码: 

int a[2][3] = { 1,2,3,4,5,6 };

void func(int(*p)[3])
{
cout << p[0][1] << endl;
}

func(a);//2


三:指针数组

指针数组就是存放指针变量的数组。这个数组里的每个元素存储的都是地址。 这个很好理解。

int * p[2];//指针数组
int a[2] = { 0 };
p[0] = &a[0];
p[1] = &a[1];

关于指针数组的应用,举一个来自《the c programming language》的一个例子,对字符串进行排序,看了下面这个例子,相信你就体会到了指针数组的好处了。

数组指针与指针数组_数组指针_03


四:总结

数组指针:指向数组的地址的指针变量,记住是数组地址;(写法例如int (*p)[2])

指针数组:一个单纯的数组,数组里存储的是指针变量。(写法例如int * p[2])

数组指针,数组+指针=指向数组的指针,实质是指针;

指针数组,指针+数组=存储指针的数组,实质是数组。