2012-12-09 20 views
1

我寫了一個函數來讀取用於fgets一個字符串使用realloc的(),使在需要時緩衝成長:計劃與realloc的行爲不同Valgrind的

char * read_string(char * message){ 
    printf("%s", message); 
    size_t buffsize = MIN_BUFFER; 
    char *buffer = malloc(buffsize); 
    if (buffer == NULL) return NULL; 
    char *p; 
    for(p = buffer ; (*p = getchar()) != '\n' && *p != EOF ; ++p) 
     if (p - buffer == buffsize - 1) { 
      buffer = realloc(buffer, buffsize *= 2) ; 
      if (buffer == NULL) return NULL; 
     } 
    *p = 0; 
    p = malloc(p - buffer + 1); 
    if (p == NULL) return NULL; 
    strcpy(p, buffer); 
    free(buffer); 
    return p; 
} 

我編譯的程序,並試了一下,它按預期工作。但是,當我用Valgrind的運行它,當讀字符串> = MIN_BUFFER和Valgrind的說,函數返回NULL:

(...) 
==18076== Invalid write of size 1 
==18076== at 0x8048895: read_string (programme.c:73) 
==18076== by 0x804898E: main (programme.c:96) 
==18076== Address 0x41fc02f is 0 bytes after a block of size 7 free'd 
==18076== at 0x402BC70: realloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so) 
==18076== by 0x8048860: read_string (programme.c:76) 
(...) 
==18076== Warning: silly arg (-48) to malloc() 
(...) 

我加* p = 0時之間的printf語句;並且p = malloc ...並且它確認參數傳遞的值是-48。 我不知道單獨和valgrind啓動時,程序不會運行相同的方式。我的代碼中是否有錯誤,或者它只是一個valgrind錯誤?

+1

Sidenote:如果realloc()返回NULL,你的代碼會泄漏內存 - 在這種情況下,在返回NULL之前使用臨時變量並釋放前一個指針。 – 2012-12-09 21:27:32

+0

'* p = 0;'可以寫出一個超出分配的大小。 – wildplasser

回答

6

重新分配緩衝區時,指針「p」仍指向舊的緩衝區。

這會壓抑內存,也會導致未來的分配使用虛假值。

+0

感謝大家:@JasonD,@davak,@ H2CO3,@MSN。你的回答很有幫助。我將代碼改爲: 'if(p - buffer == taillbuff - 1)char * r = realloc(buffer,taillbuff * = 2);如果(r == NULL){free(buffer); return NULL; } else buffer = r; p = buffer + taillbuff/2 - 1; }' – nh2

1

由於男子3 realloc的說

...該功能可以將內存塊移動到新位置。

這意味着什麼,是

p = malloc(p - buffer + 1); 

的問題。如果realloc的()被調用,緩衝區可能會指向的內存和表達

(p - buffer) 

一個新的塊沒有任何意義。

+1

「EDITED」段落不正確:'p-buffer + 1'不是一個指針,它是一個'ptrdiff_t'類型的數字。 'ptrdiff_t'是一個有符號整數類型,因此可以轉換爲兼容的整數類型,比如'size_t'。此外,您的'char'類型在修改後的代碼'p'的選擇限制了緩衝器127個字節,在這之後它溢出並通過寫入到未分配存儲器捶打堆。 – user4815162342

+0

是的,你說得對。感謝您的注意。 – davak

+0

感謝您更新答案。在C-講,'p - buffer'是*不確定的行爲*,這意味着你不僅得到一個荒謬的結果,而是一個程序可以在某些架構或編譯器崩潰。行爲未定義,因爲只允許減去指向同一數組中對象的指針;引用§6.5.6.3.9:「當減去兩個指針時,它們都應指向同一個數組對象的元素,即 或者一個超過數組對象的最後一個元素。」 (標準還在§4.2中明確規定違反的「應該」約束構成未定義的行爲。) – user4815162342

1

realloc指針返回到與相同的內容傳遞的指針所請求的大小的新緩衝器,假設在通過指針先前由mallocrealloc返回。它不保證它是相同的指針。 Valgrind很可能會修改realloc的行爲,但會將其保持在規範範圍內。

由於您正在循環調整內存大小,因此您最好通過跟蹤buffer中的位置作爲從buffer開始的偏移量而不是指針。