二维数组中的指针

389 阅读2分钟

1.父子数组

二维数组本质还是数组,不同点是,数组元素还是个数组(子数组)。 为了便于理解二维数组中的指针,这里将二维数组视为父子数组。

int a[3][4]={{1,3,5,7},{9,11,13,15},{17,19,21,23}};

a是一个二维数组名。a数组包含3行,即3个行元素;a[0],a[1],a[2]。而每一个行元素又是一个一维数组,包含4个元素(即4个列元素)。 可认为二维数组是数组的数组,对应来看,数组a是由3个一维数组所组成的。

a[0],a[1],a[2]既然是一维数组名,而C语言又规定了数组名代表数组首元素地址,因此a[0]代表一维数组 a[0]中第 0 列元素的地址,即 &a[0][0]。也就是说,a[1]的值是&a[1][0],a[2]的值是 &a[2][0]。

image.png

2.指针偏移量的问题

由之前在一维数组中的指针偏移可知,指针和数组名具有同样的作用,数组名指向数组首元素地址。

在一维数组中,p+i中的i为偏移量,而非对p进行加1,此时与指针p的变量类型有关。自增不等同于具体地址加1。 *(p+i)指向第i个偏移元素。

对应在二维数组中。a指向的是首个一维数组的地址,而首个一维数组的地址又由其内部的第一个数组元素的地址体现。因此,a=&a[0][0]; a+1=&a[1][0];a[0]=&a[0][0];a[0]+1=&a[0][1];

image.png

前已述及,a[0]和*(a+0)等价,a[1]和*(a+1)等价,a[i]和*(a+i)等价。

因此,a[0]+1和*(a+0)+1都是 &a[0][1] (即图中的2004)。

a[1]+2和*(a+1)+2的值都是 &a[1][2] (即图中的2024)。请注意不要将*(a+1)+2 错写成*(a+1+2),后者变成*(a+3)了,相当于a[3]。

那为什么a+1和(a+1)都是2016呢? a+1(是地址)和(a+1)(是内容)怎么都是同一个值呢?*

进一步分析,欲得到 a[0][1]的值,用地址法怎么表示呢?既然a[0]+1和*(a+0)+1是a[0][1]的地址,那么,* (a[0]+1)就是 a[0][1]的值。同理,((a+0)+1)或 (a+1)也是a[0][1]的值。(a[i]+j)或(*(a+i))是a[i][i]的值。

因此,*(a+i)和 a[i]是等价的。

上述内容很多,但中心思想始终没变。数组名等同于指针,指向首元素。数组名和指针的偏移量与数组元素的大小有关。若元素是int,则偏移4个字节。若元素是一个数组,则偏移4n个字节,n为数组元素中int元素的个数。

image.png