可以将多维数组的一部分看做子数组。比如说,二维数组的每一行都可以当做一维数组。这种行为会对我们用指针处理多维数组有所影响。
为了说明这种行为,我们创建一个二维数组并初始化,如下所示:
int matrix[2][5] = {{1,2,3,4,5},{6,7,8,9,10}};
然后打印元素的地址和值:
for(int i=0; i<2; i++) {
for(int j=0; j<5; j++) {
printf("matrix[%d][%d] Address: %p Value: %d\n",
i, j, &matrix[i][j], matrix[i][j]);
}
}
输出如下所示:
matrix[0][0] Address: 100 Value: 1
matrix[0][1] Address: 104 Value: 2
matrix[0][2] Address: 108 Value: 3
matrix[0][3] Address: 112 Value: 4
matrix[0][4] Address: 116 Value: 5
matrix[1][0] Address: 120 Value: 6
matrix[1][1] Address: 124 Value: 7
matrix[1][2] Address: 128 Value: 8
matrix[1][3] Address: 132 Value: 9
matrix[1][4] Address: 136 Value: 10
数组按行–列顺序存储,也就是说,将第一行按顺序存入内存,后面紧接着第二行。内存分配如下图所示。
我们可以声明一个指针处理这个数组,如下所示:
int (*pmatrix)[5] = matrix;
(*pmatrix)
表达式声明了一个数组指针,上面的整条声明语句将pmatrix
定义为一个指向二维数组的指针,该二维数组的元素类型是整数,每行有5个元素。如果我们把括号去掉就声明了5个元素的数组,数组元素的类型是整数指针。如果声明的列数不是5,用该指针访问数组的结果则是不可预期的。
如果要用指针表示法访问第二个元素(就是2),下面的代码看似合理:
printf("%p\n", matrix);
printf("%p\n", matrix + 1);
但输出却是:
100
120
matrix+1
返回的地址不是从数组开头偏移了4,而是偏移了第一行的长度,20字节。用matrix
本身返回数组第一个元素的地址,二维数组是数组的数组,所以我们得到是一个拥有5个元素的整数数组的地址,它的长度是20。我们可以用下面的语句验证这一点,它会打印出20:
printf("%d\n",sizeof(matrix[0])); // 显示20
要访问数组的第二个元素,需要给数组的第一行加上1,像这样:*(matrix[0] + 1)
。表达式matrix[0]
返回数组第一行第一个元素的地址,这个地址是一个整数数组的地址,于是,给它加1实际加上的是一个整数的长度,得到的是第二个元素。输出结果是104和2。
printf("%p %d\n", matrix[0] + 1, *(matrix[0] + 1));
我们可以用图文的形式来说明数组,如图4-11所示。
上图可以解释二维数组表示法。