問題來自於《程序員面試寶典(第三版)》第12.2節問題9(這里不評價《程序員面試寶典》,就題論題):
下面的代碼片段輸出是什么?為什么?
char *ptr; if((ptr = (char *)malloc(0))==NULL) puts("Got a null pointer"); else puts("Got a valid pointer");解析:......故意把0值傳給了函數malloc,得到了一個合法的指針,這就是上面的代碼,該代碼的輸出是"Got a valid pointer"。
這個“解析”根本就沒有解析嘛。好在查資料很方便,《C語言參考手冊》上說“如果請求的長度為0,則標准C語言函數返回一個null指針或不能用於訪問對象的非null指針。”或者你也可以直接在linux里man malloc來查閱手冊:
void *malloc(size_t size);
...
malloc() allocates size bytes and returns a pointer to the allocated memory. The memory is not cleared. If size is 0, then malloc() returns either NULL, or a unique pointer value that can later be successfully passed to free().
可見,原題的if是為了鑒別malloc()返回值是NULL,還是一個唯一的待釋放指針;而不是“解析”中的必然是非NULL的“合法指針”,因此輸出也不是確定的,盡管我用gcc和clang多次編譯運行,輸出都是"Got a valid pointer"。
順便再說說后面的代碼,同樣出自《程序員面試寶典》:
將程序改成:
char *ptr; if(int pp = (strlen(ptr=(char *)malloc(0))) == 0) puts("Got a null pointer"); else puts("Got a valid pointer");或者
char *ptr; if(int pp = (sizeof(ptr=(char *)malloc(0))) == 4) puts("Got a null pointer"); else puts("Got a valid pointer");如果求ptr的strlen的值和sizeof的值,該代碼的輸出是"Got a null pointer"。
第一段程序的分析和上面一樣,如果不幸返回了一個唯一的待釋放非NULL指針,行為不可預測;只不過這個if判斷寫的有些繁瑣:注意到“==”優先級高於"=",而賦值語句的值是其左值。
此時malloc(0)返回了一個可用於free()釋放的唯一指針(非NULL),而且將它傳給strlen(),返回值為0,這樣看來,它用'\0'進行填充的(即內容是NULL而非指針指向NULL)。但這一點並沒有在man中提到,個人猜測是和實現有關的。
除此以外,順便考察了strlen((char*)NULL)的行為:會導致段錯誤。
第二段程序呢,sizeof()里寫了一大堆,其實只是計算了sizeof(char *),在32位機上結果當然是4,而sizeof()里面的malloc()根本沒有執行。和前面兩段代碼不同,關鍵點不在malloc而是sizeof。
對於Dic4000提到的問題“實際項目中什么情況下會給malloc傳0?既然是開辟內存,傳0不是沒有意義嗎?”的個人理解:
1.一般確實不會直接寫malloc(0),但是可能在程序某個地方寫int n;int *p = malloc(n);在別的地方又令n=0,造成了參數為0的情況。若是無心而為,可能導致某種bug。如果了解malloc(0)的行為,找bug相對而言會簡單點。
2.面試題各種稀奇古怪的問題都有可能出現,有的面試官認為考這些邊界條件、特殊參數什么的能考察一個程序員的功底。
其他參考文章:
@凈壇使者進行的更深一步的挖掘,文章和回復都很有價值:關於malloc(0)的返回值問題--這兩天的總結與實踐篇
@garbageMan 談面試題:別太把面試題當回事兒
更蛋疼的問題:
如果給malloc()傳一個負參數會怎么樣?malloc()的參數是size_t類型,一般是無符號數,負值會被轉化它對應於size_t中的對應值。經我測試,當這個值大於malloc()所能分配的上限時,返回NULL。
#include <stdio.h> #include <stdlib.h> int main() { size_t t; t = (size_t)-1; printf("%u\n",t); char * p = malloc(t); if(p==NULL) printf("NULL\n"); }
(剛剛在stackoverflow上看到的http://stackoverflow.com/questions/17925771/what-happens-when-we-call-malloc-with-negative-paramter)