使用数组最容易犯的错误是数组越界和初始化错误。本节的分析仅局限于一维数组。
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 9good!