天天看點

C語言常見問題之數組越界與溢出

數組越界

C語言數組是靜态的,不能自動擴容,當下标小于零或大于等于數組長度時,就發生了越界(Out Of Bounds),通路到數組以外的記憶體。如果下标小于零,就會發生下限越界(Off Normal Lower);如果下标大于等于數組長度,就會發生上限越界(Off Normal Upper)。

C語言為了提高效率,保證操作的靈活性,并不會對越界行為進行檢查,即使越界了,也能夠正常編譯,隻有在運作期間才可能會發生問題。請看下面的代碼:

#include <stdio.h>
int main()
{
int a[3] = {10, 20, 30}, i;
for(i=-2; i<=4; i++){
printf("a[%d]=%d\n", i, a[i]);
}
return 0;
}      

運作結果:

a[-2]=-858993460

a[-1]=-858993460

a[0]=10

a[1]=20

a[2]=30

a[3]=-858993460

a[4]=-858993460

越界通路的數組元素的值都是不确定的,沒有實際的含義,因為數組之外的記憶體我們并不知道是什麼,可能是其它變量的值,可能是函數參數,可能是一個位址,這些都是不可控的。

由于C語言的”放任“,我們通路數組時必須非常小心,要確定不會發生越界。每個C語言程式員的生涯中都遇到過越界錯誤,因為越界錯誤有時候不容易發現,也不容易複現。

當發生數組越界時,如果我們對該記憶體有使用權限,那麼程式将正常運作,但會出現不可控的結果(如上例所示);如果我們對該記憶體沒有使用權限,或者該記憶體壓根就沒有被配置設定,那麼程式将會崩潰。請看下面的例子:

#include <stdio.h>
int main()
{
int a[3];
printf("%d", a[10000]);
return 0;
}      

在 VS2010 下運作,會出現運作時錯誤:

C語言常見問題之數組越界與溢出

在 C-Free 5.0 下運作,會彈出程式停止工作的對話框:

每個程式能使用的記憶體都是有限的,該程式要通路 4*10000 位元組處的記憶體,顯然太遠了,超出了程式的通路範圍。這個地方的記憶體可能沒有被配置設定,可能是系統本身占用的記憶體,可能是其它資料的記憶體,如果放任這種行為,将帶來非常危險的後果,作業系統隻能讓程式停止運作。

數組溢出

當賦予數組的元素個數超過數組長度時,就會發生溢出(Overflow)。如下所示:

int a[3] = {1, 2, 3, 4, 5};

數組長度為3,初始化時卻賦予5個元素,超出了數組容量,是以隻能儲存前3個元素,後面的元素被丢棄。

GCC、LLVM/Clang、低版本的 VS(例如 VS2010)發現數組溢出隻會給出警告,并不會報錯。但是高版本的 VS(例如 VS2015、VS2017)發現數組溢出時會報錯,禁止編譯通過,微軟終于聰明了一次。

一般情況下數組溢出不會有什麼問題,頂多是丢失多餘的元素。但是當以字元串的形式輸出字元數組時,就會産生不可控的情況,請看下面的代碼:

#include <stdio.h>
int main()
{
char str[10] = "http://c.biancheng.net";
puts(str);
return 0;
}      

在 DEV下的運作結果:

繼續閱讀