使用数组最容易犯的错误是数组越界和初始化错误。本节的分析仅局限于一维数组。
5.1.1 一维数组越界错误
【例5.1】使用数组下标越界的例子。
#include <stdio.h> int main () { int i , a[5] ; for (i=1 ;i<=5 ;i++ ) a[i]=i ; return 0 ; }
循环语句
for (i=1 ;i<=5 ;i++ ) a[i]=i ;
有两个错误。
(1)没有给数组a的第一个元素a[0]赋初值。
(2)超出了数组的尾端。一个长度为5的数组,其元素为0~4,即num[4]是最后一个元素。这种错误会造成程序运行时的时断时续的错误。
正确写法应该是:
for ( i=0 ; i<5 ; ++i ) a[i]=i ;
因为字符数组的最后一个结束标志位是\'\0\',a[5]只能存放4个字符,所以下面的语句
char a[5]=\"abcde\" ;
也产生数组越界错误。正确的写法是只能有4个字符,即
char a[5] = \"abcd\" ;
下面通过讨论C语言的这个特点,以便杜绝这种错误。
1.数值数组的边界不对称性
记住C语言数值数组是采取的不对称边界,即C语言中一个具有n个元素的数值数组,它的元素下标从0到n-1。它是从0开始,没有下标为n的元素,但有效元素是n个。
这种不对称边界反而有利于编程。假设定义5个元素的数组a[5],虽然
for ( i=0 ; i<=4 ; ++i ) a[i]=i ;
的方法是正确的。但考虑到0是第1个元素,元素数量是5,但下标5是不含在下标范围内,所以推荐使用
for ( i=0 ; i<5 ; ++i ) a[i]=i ;
的方式,而有效的元素数量=5-0=5。如果定义数组是从1开始的,显然要包含下标5,元素数量=5-1+1=5。由于使用了0,所以避免+1的运算。这就是它的优点。
虽然数组没有a[n]这个元素,但是却可以引用这个元素的地址&a[n],而且ANSI C标准也明确允许这种用法:数组中实际不存在的“溢界”元素的地址位于数组所占内存之后,这个地址可以用来进行赋值和比较,但引用该元素的值则是非法的,即不存在a[n]。
2.字符数组的边界不对称性
字符数组更为特殊,它的第n-1个元素是法定的“\0”,能存储的有效字符为n-1个。
【例5.2】下面的程序对吗?
#include <stdio.h> int main () { int i ; char a=\"abcde\" ,b[6] ; for (i=0 ;i<5 ;i++ ) b[i]=a[i] ; printf (b ); printf (\"n\" ); return 0 ; }
这个程序是错的。程序的错误是只复制5个元素。语句
char a=\"abcde\"
定义的字符数组是a[6],它具有6个元素,只是第6个元素是结束符“\0”。这个结束符必须复制到字符数组b,不然它没有结束符,造成语句
printf (b );
除了输出“abcde”之外,还将其后的字符输出(如果不是字符代码,则输出乱码),直到遇到空格才能结束。应将for语句改为:
for (i=0 ;i<6 ;i++ )
可以利用这个结束位编程,下面是一个例子。
【例5.3】利用结束位编程的例子。
#include <stdio.h> int main () { int i=0 ; char a=\"abcde\" ,b[6] ; while (a[i] !=\'\0\' ) {b[i]=a[i] ;++i ;} b[i]=\'\0\' ; i=-1 ; while (i++ ,b[i] !=\'\0\' ) printf (\"%c \" ,b[i] ); printf (\"n\" ); return 0 ; }
第1个while语句复制时,因为没有复制结束位,所以要补一个结束位。因为第2个while语句的循环要用到“i++”,所以将i的初始值设为-1,输出以结束位为结束条件。
5.1.2 一维数组初始化错误
【例5.4】初始化错误的例子。
#include <stdio.h> int main () { int i , a[5] ; char ch[5] ; a[5]={1 ,3 ,5 ,7 ,9} ; ch[5]=\"good !\" ; for (i=0 ;i<5 ;i++ ) printf (\"%d \" ,a[i] ); printf (\"n\" ); printf (ch ); printf (\"n\" ); return 0 ; }
上面语句的初始化方法不对,数组只能在定义时初始化,即
int a[5]={1 ,3 ,5 ,7 ,9} ; char ch=\"good !\" ;
字符串数组ch还产生数组越界错误,这里改为由编译识别下标。如果要直接使用下标,应该定义为:
char ch[6]=\"good !\" ;
修改后的程序如下。
#include <stdio.h> int main () { int i , a[5]={1 ,3 ,5 ,7 ,9} ; char ch=\"good !\" ; for (i=0 ;i<5 ;i++ ) printf (\"%d \" ,a[i] ); printf (\"n\" ); printf (ch ); printf (\"n\" ); return 0 ; }
运行结果为如下。
1 3 5 7 9 good !