讀古今文學網 > C語言解惑 > 5.1 一維數組越界和初始化錯誤 >

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 9
good
!