指针与数组是C/C++编程中非常重要的元素,同时也是较难以理解的。其中,多级指针与“多维”数组更是让很多人云里雾里,其实,只要掌握一定的方法,理解多级指针和“多维”数组完全可以像理解一级指针和一维数组那样简单。
首先,先声明一些常识,如果你对这些常识还不理解,那么你先去弥补一下基础知识:
1、实际上并不存在多维数组,所谓的多维数组本质上是用一维数组模拟的。
2、数组名是一个常量(意味着不允许对其进行赋值操作),其代表数组首元素的首地址。
3、数组与指针的关系是因为数组下标操作符[],比如,int a[3][2]相当于*(*(a+3)+2) 。
4、指针是一种变量,也具有类型,其占用内存空间大小和系统有关,一般32位系统下,sizeof(指针变量)=4。
5、指针可以进行加减算数运算,加减的基本单位是sizeof(指针所指向的数据类型)。
6、对数组的数组名进行取地址(&)操作,其类型为整个数组类型。
7、对数组的数组名进行sizeof运算符操作,其值为整个数组的大小(以字节为单位)。
8、数组作为函数形参时会退化为指针。
一、一维数组:
假如有一维数组如下:
char a[3];
该数组一共有3个元素,元素的类型为char,如果想定义一个指针指向该数组,也就是如果想把数组名a赋值给一个指针变量,那么该指针变量的类型应该是什么呢?前文说过,一个数组的数组名代表其首元素的首地址,也就是相当于&a[0],而a[0]的类型为char,因此&a[0]类型为char *,因此,可以定义如下的指针变量:
char * p = a;//相当于char * p = &a[0]
以上文字可用如下内存模型图表示。
大家都应该知道,a和&a[0]代表的都是数组首元素的首地址,而如果你将&a的值打印出来,会发现该值也等于数组首元素的首地址。请注意我这里的措辞,也就是说,&a虽然在数值上也等于数组首元素首地址的值,但是其类型并不是数组首元素首地址类型,也就是char *p = &a是错误的。
前文第6条常识已经说过,对数组名进行取地址操作,其类型为整个数组,因此,&a的类型是char (*)[3],所以正确的赋值方式如下:
char (*p)[3] = &a;
注:很多人对类似于a+1,&a+1,&a[0]+1,sizeof(a),sizeof(&a)等赶到迷惑,其实只要搞清楚指针的类型就可以迎刃而解。比如在面对a+1和&a+1的区别时,由于a表示数组首元素首地址,其类型为char *,因此a+1相当于数组首地址值+sizeof(char);而&a的类型为char (*)[3],代表整个数组,因此&a+1相当于数组首地址值+sizeof(a)。(sizeof(a)代表整个数组大小,前文第7条说明)
二、二维数组
假如有如下二维数组:
char a[3][2];
由于实际上并不存在多维数组,因此,可以将a[3][2]看成是一个具有3个元素的一维数组,只是这三个元素分别又是一个一维数组。实际上,在内存中,该数组的确是按照一维数组的形势存储的,存储顺序为(低地址在前):a[0][0]、a[0][1]、a[1][0]、a[1][1]、a[2][0]、a[2][1]。
为了方便理解,我画了一张逻辑上的内存图,之所以说是逻辑上的,是因为该图只是便于理解,并不是数组在内存中实际的存储模型(实际模型为前文所述)。
如上图所示,我们可以将数组分成两个维度来看,首先是第一维,将a[3][2]看成一个具有三个元素的一维数组,元素分别为:a[0]、a[1]、a[2],其中,a[0]、a[1]、a[2]又分别是一个具有两个元素的一维数组(元素类型为char)。从第二个维度看,此处可以将a[0]、a[1]、a[2]看成自己代表”第二维”数组的数组名,以a[0]为例,a[0](数组名)代表的一维数组是一个具有两个char类型元素的数组,而a[0]是这个数组的数组名(代表数组首元素首地址),因此a[0]类型为char *,同理a[1]和a[2]类型都是char *。而a是第一维数组的数组名,代表首元素首地址,而首元素是一个具有两个char类型元素的一维数组,因此a就是一个指向具有两个char类型元素数组的数组指针,也就是char(*)[2]。
也就是说,如下的赋值是正确的:
char (*p)[2] pp = a;//a为第一维数组的数组名,类型为char (*)[2]
char * p = a[0];//a[0]维第二维数组的数组名,类型为char *
同样,对a取地址操作代表整个数组的地址,类型为char (*)[3][2],所以如下赋值是正确的:
char (*p)[3][2] = &a;
三、三维数组
假设有三维数组:
char a[3][2][2];
同样,为了便于理解,特意画了如下的逻辑内存图。由于三维数组的理解方式和二维数组基本一致,因此详细的分析本文不再赘述。
四:多级指针
吃完饭接着写。。。