考虑该例子:
int calendar[12][31];
该语句声明了calendar是一个数组,该数组拥有12个数组元素,其中每个元素都是一个拥有31个整型元素的数组(而不是反过来理解)。因此,sizeof(calendar)的值是12*31=372与sizeof(int)的乘积。如果calendar不是用于sizeof的操作数,而是用于其他的场合,那么calendar总是被转换为一个指向calendar数组的起始元素的指针。要理解上面这句话的含义,就得先理解有关指针的一些细节。
任何指针都是指向某种类型的变量。
当 int a[3];
int *p;
若 这样写:p = a;
就会把数组a中下标为0的元素的地址自动赋给p。注意,这里我们并没有写成
p = &a;
这种写法在ANSIC中是非法的,因为&a是一个指向数组的指针,而p是一个指向整型变量的指针,它们的类型不匹配。
现在继续考虑最开始的“二维数组”,它其实是以数组为元素的数组。
几个声明如下:
int calendar[12][31];
int *ip;
int i;
其中calendar[4]的含义是什么? 因为calendar是一个有着12个数组类型元素的数组,它的每一个数组类型元素又是一个有着31个整型元素的数组,所以calendar[4]是calendar数组的第五个元素,是calendar数组中12个有着31个整型元素的数组之一。因此calendar[4]的行为也就表现为一个有着31个整型元素的行为。例如,sizeof(calendar[4])的结果是31与sizeof(int)的乘积。又如,
p = calendar[4];
这个语句使指针p指向数组calendar[4]中下标为0的元素。
如果calendar[4]是一个数组,我们当然可以通过下标的形式来指定这个数组中的元素,就像,
i = calendar[4][7];
我们也确实可以这样做。还是与前面类似的道理,这个语句可以写成下面这样而表达的意思保持不变:
i = *(calendar[4]+7);这个语句还可以表达成:
i = *(*(calendar+4)+7);
下面再看,
p = calendar;
这个语句是非法的。因为calendar是一个二维数组,即“数组的数组”,在此处的上下文中使用calendar名称会将其转换为一个指向数组的指针;而p是一个指向整型变量的指针,这个语句试图将一种类型的指针赋值给另一种类型的指针,所以这是非法的。
*********************
很显然 我们需要一种声明指向数组的指针的方法:
int (*ap)[31];
这个语句实际上是声明了*ap是一个拥有31个整形元素的数组,因此ap就是一个指向这样的数组的指针。因而,我们这样写,
int calendar[12][31];
int (*monthp)[31];
monthp = calendar;
这样,monthp 将指向calendar的第一个元素,即数组calendar的12个有着31个元素的数组类型元素之一。
假定在新的一年开始时,我们清空calendar数组,用下标形式可以轻易做到, int month;
for(month = 0;month < 12 ;month++){ int day;
for(day = 0;day <31;day ++)
calendar[month][day] = 0;
}
上面的代码用指针如何表示呢?
calendar[month][day] = 0;
表示为
*(*(calendar+month)+day)= 0;
但是真正有关的部分是哪一部分呢?
如果monthp指向一个拥有31个整型的数组,而calendar的元素也是拥有一个31个整型的数组,因此我们可以使用一个指针
来遍历一个数组一样,这里我们同样可以使用指针monthp以步进的方式来遍历数组calendar:
int (*monthp)[31];
for(monthp = calendar;monthp < &calendar[12;monthp++]) /*处理一个月的情况*/
同样地,我们可以处理其他数组一样,处理指针monthp所指向的数组的元素:
int (*monthp)[31];
for(monthp = calendar; monthp < &calendar[12]; monthp ++){
int *dayp;
for(dayp = *monthp;dayp<&(*monthp)[31];dayp++)
*dayp = 0;
}