2011-03-06 91 views
7
# include <stdio.h> 
# include <stdbool.h> 
# include <string.h> 
# include <stdlib.h> 

int main() 
{ 
    char * buffer; 
    buffer = malloc (2); 

    if (buffer == NULL){ 
    printf("big errors"); 
    } 
    strcpy(buffer, "hello"); 
    printf("buffer is %s\n", buffer); 
    free(buffer); 
    return 0; 
} 

我給指針/字符緩衝區分配了2個字節的內存,但是如果給它分配「hello」,它仍會打印它,而不會給我任何錯誤。爲什麼編譯器不給我一個錯誤,告訴我沒有足夠的內存分配?我閱讀了幾個問題,詢問如何檢查實際分配了多少內存,但我沒有找到具體的答案。 free函數不應該確切地知道分配給buffer的內存有多少?Malloc - >分配了多少內存?

+0

你很幸運,你沒有用你不擁有的4個額外字節覆蓋任何重要的內存片段;你每次都不會那麼幸運,而且會導致崩潰。 – holex 2015-03-04 12:38:17

回答

14

編譯器不知道。這是屬於運行時的C. malloc的歡樂和恐怖。所有的編譯器都知道,你已經告訴它它返回一個void *,它不知道要多少,或者要拷貝多少。

像valgrind這樣的工具可以檢測出其中的一些錯誤。其他編程語言使得在腳下拍攝自己變得更加困難。不是C.

+2

但是在其他語言中,當你*自己在腳下開槍時,它會把你的整條腿都踢掉! – fouronnes 2011-03-06 21:20:23

1

malloc內部分配多少取決於實現和操作系統相關(例如8個字節或更多的倍數)。即使您的編譯器和運行時沒有檢測到錯誤,您寫入未分配的字節也可能導致覆蓋其他變量的值。自由函數會記住與分配區域分開分配的字節數,例如在自由列表中。

1

爲什麼犯規編譯器給我一個 錯誤,告訴我有不是足夠 內存分配?

C不會阻止您使用您不應該使用的內存。您可以使用該內存,但它很糟糕,並導致未定義的行爲。你正在寫一本你不應該寫的地方。該程序可能顯示爲正確運行,但可能會在以後崩潰。這是UB。你不知道會發生什麼。

這就是strcpy()的情況。你寫的地方你不擁有,但語言並不能保護你。所以你應該確保你總是知道你在寫什麼和在哪裏,或者當你要超過有效的內存邊界時,確保你停下來。

我看了幾個問題是問 如何檢查 多少內存的malloc分配實際,但我沒有找到一個 具體的答案。不應該'免費' 函數必須知道有多少內存 正確地分配給'緩衝'?

malloc()可能會分配比請求的位填充更多的內存。

更多:http://en.wikipedia.org/wiki/Data_structure_alignment

free()免費-S您malloc()分配完全相同的量,但是它並不像你想象的那麼聰明。例如:

int main() 
{ 
    char * ptr = malloc(10); 
    if(ptr) 
    { 
     ++ptr; // Now on ptr+1 
     free(ptr); // Undefined Behaviour 
    } 
} 

您應該始終指向第一個塊的指針free()。做free(0)是安全的。

+0

錯字末尾? – bmargulies 2011-03-06 21:04:12

+0

@bmaurgulies,對不起。固定。 – Muggen 2011-03-06 21:04:49

1

您已寫過您分配的緩衝區的末尾。結果是未定義的行爲。有些正確選項的運行時庫至少有一些診斷類似問題的能力,但並非全部都是這樣,甚至是那些只在運行時才這樣做的功能,而且通常只有在使用正確的選項編譯時才這樣做。

4

沒有生產malloc()執行應該會阻止您嘗試寫入您分配的內容。假設你分配了123個字節,你將使用全部或者少於你分配的內容。爲了效率的緣故,不得不假定程序員要跟蹤他們的指針。

使用內存,你沒有明確,併成功地要求malloc()給你是未定義的行爲。由於malloc()實現優化字節對齊,您可能要求n字節,但得到了n + x。或者你可以寫信給黑洞。你永遠不會知道,這就是爲什麼它是未定義的行爲。

話雖這麼說...

有,讓你在statistics and debuggingmalloc()實現,但是這些需要代替標準malloc()設施的使用,就像你,如果你使用的是garbage collected variety

我還看到過嚴格爲LD_PRELOAD設計的變體,這些變體暴露了一個函數,允許您使用至少一個void指針作爲參數來定義回調函數。這個觀點期望一個包含統計數據的結構。其他工具如electric fence將簡單地停止您的程序的導致超出或訪問無效塊的確切指令。正如@R ..在評論中指出的那樣,這對調試非常有用,但效率非常低。

在這種情況下,使用堆分析器(如Valgrind及其相關工具(massif))會非常容易或者(因爲他們會說)的信息。在這個特殊的情況下,Valgrind會指出顯而易見的 - 你寫過分配的邊界。但在大多數情況下,當這不是有意的,一個好的分析器/錯誤檢測器是無價的。

使用分析器並不總是可能的,因爲:

  • 時間問題探查器下運行時(但這些都是常見隨時調用malloc()攔截)。
  • 探查不適用於你的平臺/拱
  • 調試數據(從記錄malloc())必須是

我們使用的是我在HELENOS鏈接庫的變體方案的一個組成部分(我不確定他們是否還在使用它)很長一段時間,因爲在VMM調試已知會導致瘋狂。

不過,在考慮降低替代品時,請仔細考慮未來的後果,當涉及到malloc()設施時,您幾乎總是希望使用系統所提供的功能。

+0

實際上,一個'malloc'實現可以保護你不會這樣做,如果它將'N'字節安排到頁面的最後'N'個字節,並且在它之後放置一個保護頁... :-)這是真的效率不高,但它是一個很好的調試實現。 – 2011-03-07 05:46:52

+0

@R ..爲了清晰起見,我更新了答案,我是在'爲什麼系統malloc()阻止我這樣做的背景下講話?' – 2011-03-07 23:46:35

0

Malloc - >分配了多少內存?

當您使用malloc分配內存。成功時分配內存,默認分配爲128k。第一次調用malloc會給你128k。

你要求的是buffer = malloc (2);雖然你要求2個字節。它已經分配了128k。

strcpy(buffer, "hello");分配128k塊它開始處理您的請求。 「你好」 字符串可以適應此。

這個pgm會讓你清楚。

int main() 
{ 
int *p= (int *) malloc(2);---> request is only 2bytes 

p[0]=100; 
p[1]=200; 
p[2]=300; 
p[3]=400; 
p[4]=500; 

int i=0; 

爲(;我< 5;我+ +,P ++)enter code here 的printf( 「%d \ t」 的比較,* P);

} 

第一次調用malloc。它分配128k --->來處理你的請求(2字節)。字符串「你好」可以適應它。再次調用malloc時,它會從128k處理您的請求。

超過128k它使用mmap接口。你可以參考malloc的man page。

0

沒有編譯器/平臺獨立的方式來找出多少內存malloc實際分配。 malloc的將一般分配略多於你問它在這裏看到:

http://41j.com/blog/2011/09/finding-out-how-much-memory-was-allocated/

在Linux上,你可以使用malloc_usable_size找出你可以使用多少內存。在MacOS和其他BSD平臺上,您可以使用malloc_size。上面鏈接的文章有這兩種技術的完整例子。