C语法陷阱:C语言的二维数组模拟
从前面的讨论中,我们不难得出一个推论,*a即数组a中下标为0的元素的引用。例如,我们可以这样写:
1 *a=84;
这个语句将数组a中下标为0的元素的值设置为84.同样道理,*(a+1)数组a中下标为1的的元素的引用,以此类推,概而言之,*(a+i)即数组中下标为i的元素的引用,这种写法是如此常用,因此被简记为a[i].
正是这一概念让C语言新手难于理解,实际上,由于a+i与i+a的含义一样,因此a[i]和i[a]也具有同样的含义。也许某些汇编语言程序员会发现后一种写法很熟悉,但我们绝对不推荐这种写法。
现在我们可以考虑二维数组了,正如前面所讨论的,它实际上是以数组为元素的数组,尽管我们也可以完全依据指针编写操纵一维数组的程序,这样做在一维情形下并不困难,但是对于二维数组从记法上的便利性来说采用下述形式就几乎是不可替代了。还有,如果我们仅仅使用指针来操纵二维数组,我们将不得不与C语言中最为“晦暗不明”的部分打交道,并常常遭遇到潜伏着的编译器bug。
让我们回过头来再看前面的几个声明:
1 int calendar[12][31];
2 int *p
3 int i;
然后考一考自己,calendar[4]的含义是什么?
因为calendar是一个有着12个数组类型元素的数组,它的每个数组类型元素又是一个有着31个整型数组,所以calendar[4]是 calendar数组的第五个元素,是calendar数组中12个有着31个整型元素的数组之一,因此calendar[4]的行为也就表现一个有着31个整形元素的数组的行为,例如sizeof(calendar[4])的结果是31与sizeof(int)的乘积。
1 p=calendar[4];
这个语句使指针p指向了数组calendar[4]中下标为0的元素。如果calendar[4]是一个数组,我们当然可以通过下标的形式来指定这个数组中的元素,就像下面这样:
1 i = calendar[4][7];
我们确实也可以这样做。还是与前面类似的道理,这个语句可以写成下面这样而表达式的意思保持不变:
1 i = *(calendar[4]+7);
这个语句还可以进一步写成:
1 i = *(*(calendar+4)+7);
从这里我们不难发现,用方括号的下标形式很明显地要比指针来表达简便得多。下面我们再看:
1 p = calendar;
这个语句是非法的,因为calendar是一个二维数组,即数组的数组,在此处的上下文中使用calendar名称会将其转化为一个指向数组的指针,而p是一个指向整型变量的指针,这个语句试图将一个类型的指针赋值给另一种类型的指针,所以是非法的。
很显然,我们需要一种声明指向数组的指针的方法,经过了前面对类似问题不厌其烦的讨论,构造出下面的语句应该不需要废多大力气:
1 int (*ap)[31];
这个语句的效果是,声明了*ap是一个拥有三十一个整型元素的数组ap就是一个指向这样的数组的指针,因而我们可以这样写:
1 int(*monthp)[31];
2 Monthp = calendar;
这样,monthp将指向数组calendar的第一个元素,也就是数组calendar的12个有着31个元素的数组类型元素之一。
假定在新的一年开始时,我们需要清空calendar数组,用下标形式可以很容易做到:
1 int month;
2
3 for(month=0;month < 12;month++){
4 int day;
5 for(day=0; day < 31;day++)
6 calendar[month][day]=0;
7 }
上面的代码段如果才用指针应该如何表示呢?我们很容易地把 calendar[month][day]=0; 表示为*(*(calendar+month)+day)=0;
但是真正有关的部分是哪些呢?
如果指针monthp指向一个拥有31个整型元素的数组,而calendar的元素也是一个拥有31个整型元素的数组,因此就像是在其他情况中我们可以使用一个指针遍历一个数组一样,这里我们同样可以使用指针monthp以步进的方式遍历数组calendar:
1 int (*monthp)[31];
2 for(monthp=calendar;monthp < &calendar[12];monthp++){
3 int *dayp;
4 for(dayp=*monthp;dayp < &(*monthp)[31];dayp++)
5 *dayp=0;
6 }
到目前为止,我们一路行来几乎是“如履薄冰”,而且已经走得很远,在我们跌跤之前,最好趁早悬崖勒马。尽管本节中最后一个例子是合法的ANSI C程序,但是作者还有找到一个能够让该程序顺利通过编译的编译器(译注:现在大多数的c编译器能够接受上面例子中的代码)。上面例子的讨论虽然有些偏离本书的主题,但是这个例子能够很好地揭示出C语言中数组与指针之间的独特的关系,从而更清楚明白地阐述这两个概念。
补充:软件开发 , C语言 ,