首页 » C语言解惑 » C语言解惑全文在线阅读

《C语言解惑》5.1 一维数组越界和初始化错误

关灯直达底部

使用数组最容易犯的错误是数组越界和初始化错误。本节的分析仅局限于一维数组。

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!