指针在C语言中具有举足轻重的地位,而在数组中尤其是多维数组中的应用,更是让人眼花缭乱。下面通过一个小例子来简单介绍一下二维数组中的指针。
int a[3][5]={ {1,2,3,4,5}, {6,7,8,9,10},{11,12,13,14,15} };
1. a , *a , **a ;
2. &a[0] , &a[1] , &a[0][0] , &a[1][3] ;
3. a+1 , a[0]+1 , a[1]+1 , a[1][2]+1 ;
4. *a+1 , *(a+1) , *(a+1)+3 , *(*(a+2)+3) ;
5. *(a[2]+3) ;
首先说明一下数组元素下标"[ ]"是变址运算符,相当于*( + ),即a[2]=*(a+2)。
1、首先是第一组,a是二维数组名,它表示指向0号分数组的指针常量,对应的地址字节值是该二维数组的首地址字节值。*a表示0行分数组名,等价于*(a+0),即为a[0],地址字节值依然是该二维数组的首地址字节值。但a和*a并不等价,它们的基类型字节数不同。在Dev C++编译环境中,语句printf("%d,%d,%d\n",sizeof(a),sizeof(*a)),输出的结果为60,20。所以它们的基类型字节数分别为60,20。
2、“ & ”是“取地址”运算符,所以&a[0]表示“取0行分数组的地址”,而a作为二维数组名,恰好是指向0号分数组的指针常量,所以 &a[0]=a ;同理,&a[1]表示“取第1行分数组的地址”,&a[0][0]表示“取0行0列元素所在的地址”,&a[1][3] 表示“取1行3列元素所在的地址”。
3、a表示“0行分数组的地址”,那么a+1表示“第1行分数组的地址”,等价于&a[1];a[0]是0行分数组名,表示“0行0列元素的地址”,那么a[0]+1表示“0行1列元素的地址”,等价于&a[0][1]。同理,a[1]+1表示“1行1列元素的地址”。a[1][2]表示“1行2列的元素”,a[1][2]+1表示这个元素本身的值+1。
4、前面讲到,*a表示0行分数组名,它表示“0行0列元素的地址”,则*a+1表示“0行1列元素的地址”。a+1是“1行分数组的地址”,则*(a+1)表示“1行0列元素的地址”,printf("%x,%x\n",a+1,*(a+1))这条语句输出的两个地址值是一样的,说明1行分数组的地址的确是0号元素所在的地址。若在*(a+1)前再加一个*,那么表示取该地址所表示的值,即**(a+1)=6。同理,*(a+1)+3表示“1行3列元素的地址”,*(*(a+2)+3)表示“2行3列元素的值”。
5、层层剖析,a[2]表示第2行数组名,a[2]+3表示“2行3列元素所在的地址”,*(a[2]+3)表示“2行3列元素的值”,所以*(a[2]+3)=*(*(a+2)+3),因为一开始我们就提到a[2]=*(a+2)。
【总结】:
指向多维数组元素的指针变量与指向基类型的指针变量相同。
指向多维数组的分数组的指针变量,应该指向整个一级分数组,基类型字节数为一级分数组所占字节数。
当对上述例子中的a进行+1操作时,是对a的下一级分数组进行+1;对a进行*运算时,表示进入下一级分数组。