2013-06-23 16 views
39

DatoPerché è più sicuro da usare sizeof (* puntatore) in malloc

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

Per malloc una nuova struttura,

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

è più sicuro di

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

Perché? Pensavo fossero uguali.

+8

Cordiali saluti, quando viene utilizzato con una variabile, 'sizeof' non ha bisogno di parentesi:' p = malloc (sizeof * p); ' –

+52

è più leggibile con parentesi –

+5

@TomerArazy: mi permetto di dissentire; non è leggibile con parents. Senza parents, non può essere un typename; la mancanza di parents aiuta il lettore umano a disambiguare. (problema minore: anche, i parenti potrebbero suggerire che sizeof è una funzione, che non lo è) – wildplasser

risposta

58

È più sicuro perché non è necessario menzionare il nome del tipo due volte e non è necessario creare l'ortografia corretta per la versione "dereferenziata" del tipo. Ad esempio, non c'è bisogno di "contare le stelle" in

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

Confronti che, per il tipo a base di sizeof in

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

in cui è stato anche assicurarsi che si è utilizzato il giusto numero di * sotto sizeof.

Per passare a un altro tipo, è necessario modificare solo un luogo (la dichiarazione di p) anziché due. E le persone che hanno l'abitudine di trasmettere il risultato di malloc devono cambiare tre posizioni.

Più in generale, ha molto senso attenersi alla seguente linea guida: i nomi dei tipi appartengono alle dichiarazioni e da nessun'altra parte. Le dichiarazioni effettive dovrebbero essere indipendenti dal tipo. Dovrebbero evitare di menzionare qualsiasi nome di tipo o di utilizzare qualsiasi altra caratteristica specifica del tipo il più possibile.

Quest'ultimo significa: evitare lanci non necessari. Evitare sintassi costante specifica del tipo non necessaria (come 0.0 o 0L in cui un semplice 0 è sufficiente). Evitare di menzionare i nomi dei tipi sotto sizeof. E così via.

+12

Non vale niente il fatto che, quando il tipo è cambiato, cambiandolo nella dichiarazione di p è sufficiente (non c'è bisogno di cambiarlo nel 'malloc') non significa solo che c'è meno lavoro ma che c'è meno possibilità di errore. Quindi, questo aiuta a ridurre i bug. –

+0

AndreyT, vedo il tuo punto, astrattamente parlando ... ma ti scommetto una birra non c'è mai stata una piattaforma nella storia dei computer dove sizeof (int ****)! = Sizeof (int ***):) – Josh

+0

@Josh: In pratica stai dicendo che ogni volta che devi conoscere la dimensione del puntatore, puoi semplicemente usare 'sizeof (double *)'. Sì, funzionerà, ma cose del genere dovrebbero produrre lo stesso tipo di tensione irrisolta come una parentesi sinistra ineguagliata (http://xkcd.com/859/) – AnT

19

Perché se ad un certo punto più avanti nel tempo p è fatto per puntare ad un altro tipo di struttura, allora la vostra dichiarazione di allocazione di memoria utilizzando malloc non ha bisogno di cambiare, assegna ancora abbastanza memoria richiesta per il nuovo tipo di . E assicura:

  • Non è necessario modificare la dichiarazione di allocazione della memoria ogni volta che si cambia il tipo di si alloca la memoria per.
  • Il codice è più robusto e meno soggetto a errori manuali.

In generale, è sempre buona norma non affidarsi a tipi concreti e il primo modulo lo fa, non codifica un tipo.

3

E 'conveniente, perché si può convertire questo:

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

In questa:

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

struct node *p; 
MALLOC(p); 

Oppure, per una serie:

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

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

E perché questo è sicuro? Perché l'utente che utilizza queste macro avrebbe meno probabilità di commettere errori che sono stati delineati da AndreyT, proprio come nel caso di DIM() per ottenere le dimensioni di un array statico.

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

Questo è anche più sicuro, poiché l'utente non ha bisogno di rendere le dimensioni dello array statico coerenti in più punti. Imposta le dimensioni dell'array in un posto e poi usa semplicemente lo DIM() e il gioco è fatto! Il compilatore si prende cura di te per te.

0

Non influenza direttamente la sicurezza, ma si può affermare che potrebbe prevenire un bug nelle revisioni future. D'altra parte è facile dimenticare quel piccolo *. Che ne dici di renderlo un tipo, è certamente più pulito.

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

Poi si può fare questo:

node_t *p = malloc(sizeof(node_t)); 
Problemi correlati