簡體   English   中英

malloc(0) 的意義是什么?

[英]What's the point of malloc(0)?

我剛看到這段代碼:

artist = (char *) malloc(0);

……我想知道為什么要這樣做?

根據規范, malloc(0)將返回“一個空指針或一個可以成功傳遞給 free() 的唯一指針”。

這基本上可以讓您不分配任何內容,但仍然可以放心地將“藝術家”變量傳遞給 free() 調用。 出於實際目的,這與執行以下操作幾乎相同:

artist = NULL;

C 標准 (C17 7.22.3/1) 說:

如果請求的空間大小為零,則行為是實現定義的:要么返回空指針,要么行為就像大小是某個非零值,除了返回的指針不得用於訪問對象。

因此, malloc(0)可能會返回NULL可能無法取消引用的有效指針。 在任何一種情況下,對其調用free()完全有效的。

我真的不認為malloc(0)有多大用處,除非在循環中調用malloc(n)情況下,例如, n可能為零。

看了鏈接里的代碼,相信作者有兩個誤解:

  • malloc(0)總是返回一個有效的指針,並且
  • free(0)不好。

因此,他確保artist和其他變量始終具有某些“有效”值。 評論說得一樣多: // these must always point at malloc'd data

malloc(0) 行為是特定於實現的。 該庫可以返回 NULL 或具有常規 malloc 行為,而無需分配內存。 無論它做什么,它都必須在某處記錄。

通常,它返回一個有效且唯一的指針,但不應取消引用。 還要注意,即使它實際上沒有分配任何東西,它也可以消耗內存。

可以重新分配一個非空的 malloc(0) 指針。

但是,逐字逐字地使用 malloc(0) 並沒有多大用處。 它主要用於動態分配為零字節並且您不關心驗證它的情況。

本頁其他地方有一個答案,開頭是“malloc(0) 將返回一個有效的內存地址,其范圍將取決於正在分配內存的指針類型”。 這個陳述是不正確的(我沒有足夠的聲譽直接評論那個答案,所以不能把這個評論直接放在那里)。

執行 malloc(0)不會自動分配正確大小的內存。 malloc 函數不知道您將其結果轉換為什么。 malloc 函數完全依賴於您作為參數提供的大小數字。 您需要執行 malloc(sizeof(int)) 以獲得足夠的存儲空間來保存 int,例如,不是 0。

malloc(0)對我來說沒有任何意義,除非代碼依賴於特定於實現的行為。 如果代碼是可移植的,那么它必須考慮到malloc(0)的 NULL 返回不是失敗的事實。 那么為什么不直接將 NULL 分配給artist ,因為這是一個有效的成功結果,並且代碼更少,並且不會導致您的維護程序員花時間弄清楚它?

malloc(SOME_CONSTANT_THAT_MIGHT_BE_ZERO)malloc(some_variable_which_might_be_zero)可能有它們的用途,盡管如果值為 0,您必須再次注意不要將 NULL 返回視為失敗,但 0 大小應該是可以的。

這里有很多半真半假的答案,所以這里是鐵的事實。 malloc()的手冊頁說:

如果 size 為 0,則 malloc() 返回 NULL 或稍后可以成功傳遞給 free() 的唯一指針值。

這意味着,絕對不能保證malloc(0)的結果是唯一的或不是 NULL。 唯一的保證是由free()的定義提供的,這里是手冊頁的內容:

如果 ptr 為 NULL,則不執行任何操作。

因此,無論malloc(0)返回什么,都可以安全地傳遞給free() 但是NULL指針也可以。

因此,寫作artist = malloc(0); 絕不會比寫artist = NULL;更好artist = NULL;

為什么你不應該這樣做......

由於 malloc 的返回值取決於實現,因此您可能會得到一個 NULL 指針或其他一些地址。 如果錯誤處理代碼不檢查大小和返回值,這最終可能會導致堆緩沖區溢出,從而導致穩定性問題(崩潰)甚至更糟的安全問題。

考慮這個例子,通過返回的地址進一步訪問內存將破壞堆,如果大小為零並且實現返回一個非 NULL 值。

size_t size;
 
/* Initialize size, possibly by user-controlled input */
 
int *list = (int *)malloc(size);
if (list == NULL) {
  /* Handle allocation error */
}
else {
  /* Continue processing list */
}

請參閱 CERT 編碼標准中的此安全編碼頁面,我以上面的示例為進一步閱讀。

誠然,我以前從未見過這個,這是我第一次看到這種語法,可以說,函數矯枉過正的經典案例。 結合里德的回答,我想指出有一個類似的東西,它看起來像一個重載的函數realloc

  • foo 為非 NULL 且大小為零, realloc(foo, size); . 當您將非 NULL 指針和大小為零傳遞給 realloc 時,realloc 的行為就像您調用了 free(...)
  • foo 為 NULL 且 size 非零且大於 1, realloc(foo, size); . 當您傳入一個 NULL 指針並且大小不為零時,realloc 的行為就像您調用了 malloc(...)

希望這會有所幫助,最好的問候,湯姆。

實際回答提出的問題:沒有理由這樣做

在 Windows 中:

  • void *p = malloc(0); 將在本地堆上分配一個零長度的緩沖區。 返回的指針是一個有效的堆指針。
  • malloc最終使用默認的 C 運行時堆調用HeapAlloc ,然后調用RtlAllocateHeap等。
  • free(p); 使用HeapFree釋放堆上的長度為 0 的緩沖區。 不釋放它會導致內存泄漏。

它實際上非常有用,並且(顯然恕我直言),返回空指針的允許行為已被破壞。 動態指針不僅對於它所指向的內容有用,而且對於它的地址是唯一的這一事實也很有用。 返回 NULL 將刪除第二個屬性。 我編程的所有嵌入式 malloc(實際上很頻繁)都有這種行為。

不確定,根據我發現的一些隨機 malloc 源代碼,輸入 0 會導致返回值為 NULL。 所以這是一種將藝術家指針設置為 NULL 的瘋狂方式。

http://www.raspberryginger.com/jbailey/minix/html/lib_2ansi_2malloc_8c-source.html

malloc(0) 將返回 NULL 或一個可以正確傳遞給 free 的有效指針。 盡管它指向的內存似乎沒有用或無法寫入或讀取,但這並不總是正確的。 :)

int *i = malloc(0);
*i = 100;
printf("%d", *i);

我們預計這里會出現分段錯誤,但令人驚訝的是,這會打印 100! 這是因為當我們第一次調用 malloc 時,malloc 實際上要求了一大塊內存。 之后每次調用 malloc 都會使用那個大塊的內存。 只有在那個巨大的塊結束后,才會要求新的內存。

malloc(0) 的使用:如果您希望后續 malloc 調用更快,則調用 malloc(0) 應該為您完成(邊緣情況除外)。

下面是用valgrind內存檢查工具運行后的分析。

==16740== Command: ./malloc0
==16740==
p1 = 0x5204040
==16740==
==16740== HEAP SUMMARY:
==16740==     in use at exit: 0 bytes in 0 blocks
==16740==   total heap usage: 2 allocs, 2 frees, 1,024 bytes allocated
==16740==
==16740== All heap blocks were freed -- no leaks are possible

這是我的示例代碼:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
   //int i;
   char *p1;

   p1 = (char *)malloc(0);
   printf("p1 = %p\n", p1);

   free(p1);

   return 0;

}

默認情況下分配 1024 個字節。 如果我增加 malloc 的大小,分配的字節將增加 1025 等等。

根據Reed Copsey 的回答和 malloc 的手冊頁,我寫了一些示例進行測試。 我發現 malloc(0) 總是會給它一個唯一的值。 看我的例子:

char *ptr;
if( (ptr = (char *) malloc(0)) == NULL )
    puts("Got a null pointer");
else
    puts("Got a valid pointer");

輸出將是“得到一個有效的指針”,這意味着ptr不為空。

只是為了糾正這里的錯誤印象:

artist = (char *) malloc(0); 永遠不會返回NULL 它與artist = NULL; . 編寫一個簡單的程序並將artistNULL進行比較。 if (artist == NULL)為假而if (artist)為真。

malloc(0)將返回一個有效的內存地址,其范圍將取決於正在分配內存的指針類型。 您也可以為內存區域分配值,但這應該在所使用的指針類型的范圍內。 您還可以釋放分配的內存。 我將用一個例子來解釋這一點:

int *p=NULL;
p=(int *)malloc(0);
free(p);

上面的代碼在 Linux 機器上的gcc編譯器中可以正常工作。 如果您有 32 位編譯器,那么您可以提供整數范圍內的值,即 -2147483648 到 2147483647。同樣適用於字符。 請注意,如果聲明的指針類型發生變化,則無論malloc類型轉換如何,值的范圍都會發生變化,即

unsigned char *p=NULL;
p =(char *)malloc(0);
free(p);

p將取一個從 0 到 255 的 char 值,因為它被聲明為一個 unsigned int。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM