2012-07-18 119 views
7

我試圖抓住malloc函數在C,和我寫以下代碼:Ç - malloc和陣列混亂

int i; 

int *arr = (int*)malloc(5*sizeof(int)); 

if(arr==NULL){ 

    printf("Failed to allocate memory for arr...\n"); 
    exit(1); 

} 

我認爲,這表示,只有5個元素可以被添加到陣列中。爲了測試這是否屬實,我添加了以下代碼:

arr[0] = 1; 
arr[1] = 2; 
arr[2] = 3; 
arr[3] = 4; 
arr[4] = 5; 
arr[5] = 6; 
arr[6] = 7; 
arr[7] = 8; 
arr[8] = 9; 

for(i=0;i<9;i++){ 

    printf("%d\n",arr[i]); 

} 

令人驚訝的是,該代碼編譯和運行完美。這怎麼可能?

+0

一旦你已經明白了這一點(基於人們給出的答案或其他方式),看看[緩衝區溢出](http://en.wikipedia.org/wiki/Buffer_overrun)。有趣和有趣的。 – 2012-07-18 23:06:25

回答

9

C不強制執行任何數組邊界檢查,所以當您請求5個整數的空間時,您使用了更多。

實際上,您覆蓋了4個內存位置,這些位置確實沒有爲您的特定目的而預留。你的程序去過去爲您的陣列留出的內存區域,並開始將值存儲在分配區域之外的內存中。

這個「工作」的事實只是純粹的運氣,而不是依賴的東西。它可能會在接下來的100次中運行,或者它可能會在您嘗試時失敗,最有可能是「分段錯誤」消息。

防禦性編程,像你這樣的理智檢查的malloc的返回值,被銘記的是負責邊界檢查,編譯代碼具有較高的警告級別上啓用等一些防範這些最好的防禦錯誤的種類。其他工具,如valgrind,棉絨類型的跳棋也可以提供幫助,但最終取決於您。

作爲C最大的優勢之一,它做各種事情的自由度低,高水平,也是IMO最大的弱點之一。如果Java是一輛沃爾沃,C也許更像是一輛有時會出現突然中斷的法拉利:)

+1

Malloc分配一塊內存,這個內存至少會被請求的大小。它可能會更大,這取決於malloc的實現。它不會將內存清零。您可以從陣列的末尾訪問內存,並且可以從分配的塊的末尾訪問內存。你會得到隨機的「垃圾」。 – webjprgm 2012-07-18 22:51:53

+1

@webjprgm從來沒有真正考慮過'malloc/calloc'分配的內存多於請求的內存。爲了「清零」內存'calloc'應該是合適的。 – Levon 2012-07-18 22:54:51

+0

另請注意,如果無限期地繼續for循環,當您到達程序的分配頁面的末尾時,它可能會導致段錯誤。 – webjprgm 2012-07-18 22:57:23

0

C沒有做邊界檢查。

0

這怎麼可能?

你正在寫數組的末尾。因爲C中沒有邊界檢查,所以doesn't cause the program to crash(立即),但是,如果寫入足夠多,它最終會導致錯誤。有時你可能能夠寫出數百個int值,而有時候你可能無法寫入任何額外的值。

0

計算機中的內存基本上是按順序排列的。你問malloc給你一小塊內存 - 足夠5個整數。計算機中的可用內存肯定比分配長度爲5的數組要多得多。因此,如果您要寫入或從arr[8]讀取數據,則需要在內存中寫入其他位置。

通常情況下,現代計算機有太多的內存,你可能正在寫一個未使用的地方。但偶爾,你會不小心覆蓋其他一些其他的malloc'd數據。

請注意,有時您的程序將崩潰(如您所料)。這是因爲你可能試圖在你分配的內存之外寫的太遠,以至於地址不再有效。您的操作系統通常會捕獲該程序併爲您崩潰程序。