二维数组
c语言按照行主序存储二维数组。也就是说,二维数组元素在内存中的位置是连续的,每行末尾元素(若不是最后一行)的下一个元素就是下一行的首元素。
如下图所示
接下来我们来分析一下如何将二维数组所有元素初始化零。
假设数组的声明如下:
int a[NUM_ROWS][NUM_COLS];
普通的写法是利用两层for循环
int row, col;for (row = 0; row < NUM_ROWS; row++)for (col = 0; col < NUM_COLS; col++)a[row][col] = 0;
我们可以利用指针操作,将二维数组看成一个一维的大数组,其元素数量为NUM_ROWS*NUM_COLS,利用一个for循环完成操作
int *p;for (p = &a[0][0]; p <= &a[NUM_ROWS-1][NUM_COLS-1]; p++)*p = 0;
不过虽然代码量减少了,但实际上程序运行的次数和前者两层for循环操作运行次数是一样的。(这类方法明显破坏了程序的可读性,但是至少对一些老的编译器来说这种方法在效率方面进行了补偿。不过,对许多现代的编译器来说,这样所获得的速度优势往往极少甚至完全没有。)
接下来我们再看一个例子:将二维数组第i行的元素置0
为了访问到第i行的元素,让p指向数组a中第i行的第一个元素:
p=&a[i][0];
实际上,我们还可以将这句代码简写为
p=a[i];
对于任意一维数组a[]来说,其首元素地址为a。而二维数组可以看成是多个一维数组,行数就是一维数组的个数,列数就是数组中元素的个数。由此第i行的首元素地址就为a[i]。
如果要正经推导的话:对于任意数组a来说,表达式a[i]等价于(a + i)。因此&a[i][0]等同于&((a[i] + 0)),而后者等价于&a[i];又因为&和运算符可以抵消,也就等同于a[i]。
那么代码为:
int a[NUM_ROWS][NUM_COLS], *p, i;for (p = a[i]; p < a[i] + NUM_COLS; p++)*p = 0;
接下来我们再来思考一下怎么将数组a的第i列的元素置零呢?
我们可以利用数组指针(指向数组的指针)来实现这点。如声明一个数组指针:
int (*p)[NUM_COLS]
。
我们知道,c语言指针每次自增1时,内存地址增加的量即为指针指向类型的所占内存单元数。在这里,p指向一个元素个数为NUM_COLS的int型数组,那么p++将会导致p指向地址增加NUM_COLS*(int型所占地址单元个数),这就实现了p从这一行指向了下一行。
代码如下
for(p = &a[0]; p < &a[NUM_ROWS]; p++){(*p)[i] = 0;}
最后,如果我们想遍历整个数组的话,也可以将整个二维数组看成一整个一维数组,利用指针进行遍历。
int *t;for(t = a[0]; t <= &a[NUM_ROWS-1][NUM_COLS-1]; t++)printf(\"%d \",*t);