数组指针和指针数组是两个很容易让初学者感到模糊的概念,同时也是重点,所以希望读者能耐心阅读,仔细理解。
那么,什么是数组指针,什么又是指针数组呢?
在继续分析两者的区别前,需要读者了解3个问题:
1.二维数组是特殊的一维数组。
我们发现输出的地址是连续的,很简单,不作解释。
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.数组类型可以转化为指针类型。
在VS调试下,监视变量图为:
我们知道,运算符=成立的前提是左右类型相同或者右类型可以转化为左类型。
在上图,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组成。
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个,无法转化。
关于数组指针的应用,应该就是传递参数的时候了,看下面的代码:
指针数组就是存放指针变量的数组。这个数组里的每个元素存储的都是地址。 这个很好理解。
关于指针数组的应用,举一个来自《the c programming language》的一个例子,对字符串进行排序,看了下面这个例子,相信你就体会到了指针数组的好处了。
数组指针:指向数组的地址的指针变量,记住是数组地址;(写法例如int (*p)[2])
指针数组:一个单纯的数组,数组里存储的是指针变量。(写法例如int * p[2])
数组指针,数组+指针=指向数组的指针,实质是指针;
指针数组,指针+数组=存储指针的数组,实质是数组。