2013-06-23 70 views
39

鑑於爲什麼可以更安全地使用sizeof(*指針)中的malloc

struct node 
{ 
    int a; 
    struct node * next; 
}; 

對malloc一個新的結構,

struct node *p = malloc(sizeof(*p)); 

struct node *p = malloc(sizeof(struct node)); 

爲什麼安全?我認爲他們是一樣的。

+8

僅供參考,使用一個變量時,'sizeof'不需要括號:'P =的malloc(*的sizeof P);' –

+52

它更可讀與parens –

+5

@TomerArazy:我不同意;它與parens無關。沒有parens,它不能是一個類型名;缺乏幫助人類讀者消除歧義。 (小問題:另外,parens可能會建議sizeof是一個函數,但它不是) – wildplasser

回答

58

這是比較安全的,因爲您不必提及類型名稱兩次,也不必爲類型的「取消引用」版本構建適當的拼寫。例如,你不必在

int *****p = malloc(100 * sizeof *p); 

以「數星星」與此相比,該型爲基礎的

int *****p = malloc(100 * sizeof(int ****)); 

sizeof,你必須得確保你使用正確的號碼*根據sizeof

爲了切換到另一種類型,您只需更換一個位置(聲明p)而不是兩個。而有鑄造malloc結果習慣的人必須換三個地方。

更一般地說,堅持以下準則是很有意義的:類型名稱屬於聲明而不屬於其他地方。實際的語句應該是類型無關的。他們應儘可能避免提及任何類型名稱或使用任何其他類型特定的功能。

後者意味着:避免不必要的強制轉換。避免不必要的類型特定的常量語法(如0.00L,其中一個普通的0就足夠了)。避免提及sizeof下的類型名稱。等等。

+12

值得一提的是,當類型改變時,在p的聲明中改變它就足夠了(不需要在'malloc'中改變它)不僅意味着工作量減少,而且還有錯誤的可能性較小。因此,這有助於減少錯誤。 –

+0

AndreyT,我明白你的觀點,抽象地說......但是我敢打賭你會有啤酒,從來沒有在電腦歷史上的一個平臺,其中sizeof(int ****)!= sizeof(int ***): ) – Josh

+0

@Josh:你基本上說每次你需要知道指針的大小,你可以使用'sizeof(double *)'。是的,它會起作用,但類似的事情應該產生與無法匹配的左括號相同的未解決的緊張局勢(http://xkcd.com/859/) – AnT

19

因爲如果在時間p一些後點作爲指向另一個結構類型,然後使用malloc你的內存分配語句沒有改變,它仍然對分配的新類型需要足夠的內存。它確保:

  • 您不必每次更改它分配內存的時間來修改內存分配的聲明。
  • 您的代碼更健壯,不太容易出現手動錯誤。

一般來說,不要依賴具體的類型並且第一種形式就是這樣做,它不會硬編碼類型。

3

這是方便,因爲你可以把這樣的:

struct node *p= malloc(sizeof(*p)); 

進入這個:

#define MALLOC(ptr) (ptr) = malloc(sizeof(*(ptr))) 

struct node *p; 
MALLOC(p); 

或爲一個數組:

#define MALLOC_ARR(ptr, arrsize) \ 
     (ptr) = malloc(sizeof(*(ptr)) * arrsize) 

struct node *p; 
MALLOC_ARR(p, 20); 

爲什麼是這樣安全嗎?因爲使用這些宏的用戶不太可能犯AndreyT勾畫的錯誤,就像在DIM()的情況下獲得靜態數組的大小一樣。

#define DIM(arr) ((sizeof(arr))/(sizeof(arr[0]))) 

這也更安全,因爲用戶不需要在幾個地方使靜態數組大小保持一致。將陣列大小設置在一個位置,然後使用DIM()即可完成!編譯器爲你處理它。

0

它不直接影響安全性,但可以聲稱它可以防止未來版本中的錯誤。另一方面,很容易忘記那個小小的*。如何使它成爲一種類型,它肯定是更清潔的。

typedef struct node 
{ 
    int a; 
    struct node * next; 
} node_t; 

然後,你可以這樣做:

node_t *p = malloc(sizeof(node_t)); 
相關問題