|
數(shù)組越界C語言數(shù)組是靜態(tài)的,不能自動(dòng)擴(kuò)容,當(dāng)下標(biāo)小于零或大于等于數(shù)組長度時(shí),就發(fā)生了越界(Out Of Bounds),訪問到數(shù)組以外的內(nèi)存。如果下標(biāo)小于零,就會(huì)發(fā)生下限越界(Off Normal Lower);如果下標(biāo)大于等于數(shù)組長度,就會(huì)發(fā)生上限越界(Off Normal Upper)。
C語言為了提高效率,保證操作的靈活性,并不會(huì)對越界行為進(jìn)行檢查,即使越界了,也能夠正常編譯,只有在運(yùn)行期間才可能會(huì)發(fā)生問題。請看下面的代碼:
#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;
}
運(yùn)行結(jié)果:a[-2]=-858993460a[-1]=-858993460a[0]=10a[1]=20a[2]=30a[3]=-858993460a[4]=-858993460
越界訪問的數(shù)組元素的值都是不確定的,沒有實(shí)際的含義,因?yàn)閿?shù)組之外的內(nèi)存我們并不知道是什么,可能是其它變量的值,可能是函數(shù)參數(shù),可能是一個(gè)地址,這些都是不可控的。
由于C語言的”放任“,我們訪問數(shù)組時(shí)必須非常小心,要確保不會(huì)發(fā)生越界。每個(gè)C語言程序員的生涯中都遇到過越界錯(cuò)誤,因?yàn)樵浇珏e(cuò)誤有時(shí)候不容易發(fā)現(xiàn),也不容易復(fù)現(xiàn)。
當(dāng)發(fā)生數(shù)組越界時(shí),如果我們對該內(nèi)存有使用權(quán)限,那么程序?qū)⒄_\(yùn)行,但會(huì)出現(xiàn)不可控的結(jié)果(如上例所示);如果我們對該內(nèi)存沒有使用權(quán)限,或者該內(nèi)存壓根就沒有被分配,那么程序?qū)?huì)崩潰。請看下面的例子:
#include <stdio.h>
int main()
{
int a[3];
printf("%d", a[10000]);
return 0;
}
在 VS2010 下運(yùn)行,會(huì)出現(xiàn)運(yùn)行時(shí)錯(cuò)誤:
1.jpg (24.12 KB, 下載次數(shù): 60)
下載附件
2022-8-26 11:32 上傳
在 C-Free 5.0 下運(yùn)行,會(huì)彈出程序停止工作的對話框:
每個(gè)程序能使用的內(nèi)存都是有限的,該程序要訪問 4*10000 字節(jié)處的內(nèi)存,顯然太遠(yuǎn)了,超出了程序的訪問范圍。這個(gè)地方的內(nèi)存可能沒有被分配,可能是系統(tǒng)本身占用的內(nèi)存,可能是其它數(shù)據(jù)的內(nèi)存,如果放任這種行為,將帶來非常危險(xiǎn)的后果,操作系統(tǒng)只能讓程序停止運(yùn)行。
數(shù)組溢出當(dāng)賦予數(shù)組的元素個(gè)數(shù)超過數(shù)組長度時(shí),就會(huì)發(fā)生溢出(Overflow)。如下所示:int a[3] = {1, 2, 3, 4, 5};數(shù)組長度為3,初始化時(shí)卻賦予5個(gè)元素,超出了數(shù)組容量,所以只能保存前3個(gè)元素,后面的元素被丟棄。
GCC、LLVM/Clang、低版本的 VS(例如 VS2010)發(fā)現(xiàn)數(shù)組溢出只會(huì)給出警告,并不會(huì)報(bào)錯(cuò)。但是高版本的 VS(例如 VS2015、VS2017)發(fā)現(xiàn)數(shù)組溢出時(shí)會(huì)報(bào)錯(cuò),禁止編譯通過,微軟終于聰明了一次。
一般情況下數(shù)組溢出不會(huì)有什么問題,頂多是丟失多余的元素。但是當(dāng)以字符串的形式輸出字符數(shù)組時(shí),就會(huì)產(chǎn)生不可控的情況,請看下面的代碼:
#include <stdio.h>
int main()
{
char str[10] = "88888888888888888888";
puts(str);
return 0;
}
在 DEV下的運(yùn)行結(jié)果:
2.jpg (37.35 KB, 下載次數(shù): 61)
下載附件
2022-8-26 11:33 上傳
字符串的長度大于數(shù)組長度,數(shù)組只能容納字符串的前面一部分,也就是"http://c.b",即使編譯器在最后添加了'\0',它也保存不到數(shù)組里面,所以 printf() 掃描數(shù)組時(shí)不會(huì)遇到結(jié)束符'\0',只能繼續(xù)向后掃描。而后面內(nèi)存中的數(shù)據(jù)我們不知道是什么,字符能否識(shí)別,何時(shí)遇到'\0',這些都是不確定的。當(dāng)字符無法識(shí)別時(shí),就會(huì)出現(xiàn)亂碼,顯示奇怪的字符。
由此可見,在用字符串給字符數(shù)組賦值時(shí),要保證數(shù)組長度大于字符串長度,以容納結(jié)束符'\0'。
總結(jié):能夠理解數(shù)組越界和數(shù)組溢出的原因,并且在編程中注意避免。
|
|