关于二维数组:
如果数组的维数大于1,我们就说他是一个多维数组,例如如下的声明
int array[10][4];
就说明他是一个二维数组。但是这到底是表示的是一个10行每行有4个元素,还是4行每行有10个元素呢?可能下面的一个比较有
助于分清他们的区别:
int a; int b[10]; int c[3][4]; int d[3][4][4];
其中第一行将a声明为一个简单整数,第二行将b声明为一个有10个元素的向量,然后剩下的每一行在前一行的基础上增加一
个维度,第三行表示c是一个有3个元素的向量,他和b的不同点就在与b中的每个元素都是一个标量,而c中的每一个元素又是一个向
量。那么最后一行的d又该怎样的理解呢?我们可以用分析c的方法继续分析d,首先第一数3表示他是一个有3个元素的数组,每个元
素又是一个4个元素的数组,而这4个元素中的每个元素又是一个包含4个整型元素的数组。d就像是我们运动会时的队列,每个学院
选一些人出来站成一个4x4的方正。上个图给分析一下:
![]()
![]()
看图的花估计更清楚一点,不过有一点我们必须清楚,声明一个变量时,其中存储的是对象的地址,还有一点就是在计算机数组的
存储方式并不像我们画的这样,而是连续存储的,这个可以通过下面的代码验证:
该段代码的运行结果为:1 #include <stdio.h> 2 3 int main() 4 { 5 int array_b[2][4] = { {1,2,3,4}, 6 {23,21,32,32}}; 7 int i,j; 8 //打印数组中的每个元素 9 for(i = 0;i < 2;i++) 10 { 11 for(j = 0;j < 4;j++) 12 printf("%d\t",array_b[i][j]); 13 printf("\n"); 14 } 15 //打印数组中每个元素的地址 16 for(i = 0;i < 2;i++) 17 { 18 for(j = 0;j < 4;j++) 19 printf("%p\t",*(array_b + i) + j); 20 printf("\n"); 21 } 22 return 0; 23 }
123 4
23 21 3232
0xbfef88a8 0xbfef88ac0xbfef88b00xbfef88b4
0xbfef88b8 0xbfef88bc0xbfef88c00xbfef88c4从其中也验证了数组中元素是存储连续的这一特点。
关于数组名:
一维数组名的值是一个指向存储类型的常指针(类似与 type * const name),其指向数组的第一个元素。如果理解这一点的话想想
二维数组也就简单了,唯一的区别就是多维数组的第一维的元素又是一个数组。那么如上面的声明 int c[3][4] 中的数组名c是一个指向有10个元素的数组的指针。
那么怎样声明一个指向二维数组的指针呢?如果是一个以为数组的话很简单我们可以这样声明一个指向一维数组的指针:
int *ptr = b;
关键就在于二维数组名并不是一个指向整型的指针,而是一个指向整型数组的指针。一个合理的办法是声明一个指针指向一个
一维数组。
int (*ptr)[4] = c;
这个表达式到底应该怎样理解呢?由于括号的作用ptr首先和*结合,所以,pr是一个指针,那他指向什么呢?接下来的进行的是下标操作,所以就可以认定其指向的是一个某种类型的数组。
有一个更棘手的问题摆在了我们的面前,怎样同通过一个指向二维数组的指针访问数组中的元素?假设我们声明了一个二维数
组 int a[3][5]; 并且用一个指针指向了二维数组c int (*ptr)[5] = a; 因此,表达式ptr就是指向第一个子数组的指针, ptr +1 就是指向第
二个子数组的指针。
![]()
因此,*ptr + 2 和*(ptr + 1) + 3也就比较好理解啦,*ptr + 2 表示第一个子数组中的第三个元素,*(ptr + 1) + 3 表示第二个子数组中的第四个元素。
小结:
在没有特殊要求的情况下还是应该选择下标来操作二维数组,这样的话,别人理解起来就能容易。