目录
如何识别二维数组:
对于二维数组b[2][5],
[2]:第一个维度,表示 b 这个数组中有两个元素;
[5]:第二个维度,表示第一维度的每个元素内部有5个元素。
数组名代表数组首元素的地址,这句话对一维、二维数组都适用。
对于一维数组 int a[5]:数组名 a 表示首元素 a[0] 的地址,即 a = &a[0];
对于二维数组 b[2][5]:b[0] 对于整个数组 b 来说,它是首元素(两个元素 b[0]、b[1]),同时它也是b[0]这个一维数组的数组名。所以,b[0] 等价于&b[0][0]。b[1] 同理。
访问二维数组的两种方式:
1. 普通指针指向二维数组的第一维
对于二维数组b[2][5],
从第一维度去看,该数组中的 b[0]、b[1] 是两个一维的int型数组。
而 b[0]、b[1]都是数组名,分别代表b[0][0]和b[1][0]的地址,所以指向二维数组的第一维如下:
int* p1 = b[0];
int* p2 = b[1];
此时的用法和一维数组一样:
printf("b[0][0] = %d\n",*p1);
printf("b[0][1] = %d\n",*(p1+1));
printf("b[1][0] = %d\n",*p2);
printf("b[1][1] = %d\n",*(p2+1));
2. 数组指针访问二维数组
对于二维数组b[2][5],
数组名 b 就表示首元素 b[0] 的地址,即数组名 b 等价于 &b[0];
而 b[0] 不仅是该二维数组的首元素,同时也是一个一维数组的数组名;
所以,&b[0] 就相当于对数组名再次取地址,那么继续对数组名取地址又表示什么意思呢?
假设有一个数组 int a[5],则数组名 a 表示首元素 a[0] 的地址,&a 表示整个数组的地址(而不再是首元素的地址)。
数组指针就是用来指向整个数组的地址,其类型为 int(*)[] 。
所以上述二维数组中的 &b[0],以及 b 都是和这种类型匹配的,或者说就是这种类型。
回到最初的例子,二维数组 b[2][5] 的数组名 b 等价于 &b[0],而 &b[0] 是对数组名再次取地址,即 &b[0] 和 int(*)[] 类型匹配。所以有:
int(*p)[5] = b = &b[0];
我们知道,取值和解引用是两个反向的过程, &b[0] 是对地址(数组名)再次取址,那么可以认为,要用数组指针 p 访问到数据,必须经过两次解引用。
数组名 b 和指针 p 是同一种类型,int(*)[5];
又 b = &b[0],解引用后得到 b[0],则 *p = b[0];
又 b[0] 是数组名,再次解引用,得到 *(*p) = b[0][0];
结论:b[i][j] = *(*(p+i)+j) 。