使用數組最容易犯的錯誤是數組越界和初始化錯誤。本節的分析僅局限於一維數組。
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 !