web-dev-qa-db-fra.com

Pourquoi est-il plus sûr d'utiliser sizeof (* pointeur) dans malloc

Donné

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

Pour malloc une nouvelle structure,

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

est plus sûr que

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

Pourquoi? Je pensais que c'était pareil.

41
Yu Hao

Il est plus sûr car vous n'avez pas à mentionner le nom du type deux fois et vous n'avez pas à créer l'orthographe appropriée pour la version "déréférencée" du type. Par exemple, vous n'avez pas à "compter les étoiles" dans

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

Comparez cela au sizeof basé sur le type dans

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

où vous avez aussi assurez-vous d'avoir utilisé le bon nombre de * sous sizeof.

Pour passer à un autre type, il suffit de changer un endroit (la déclaration de p) au lieu de deux. Et les gens qui ont l'habitude de lancer le résultat de malloc doivent changer trois endroits.

Plus généralement, il est très logique de s'en tenir à la directive suivante: les noms de type appartiennent aux déclarations et nulle part ailleurs. Les instructions réelles doivent être indépendantes du type. Ils doivent éviter de mentionner des noms de type ou d'utiliser autant que possible d'autres fonctionnalités spécifiques au type.

Ce dernier signifie: Évitez les lancers inutiles. Évitez la syntaxe constante spécifique au type inutile (comme 0.0 ou 0L où une plaine 0 suffirait). Évitez de mentionner les noms de type sous sizeof. Etc.

62
AnT

Parce que si à un moment ultérieur, p est fait pour pointer vers un autre type de structure, votre instruction d'allocation de mémoire utilisant malloc n'a pas besoin de changer, elle alloue toujours suffisamment de mémoire requise pour le nouveau type. Il garantit:

  • Vous n'avez pas à modifier l'instruction d'allocation de mémoire chaque fois que vous modifiez le type pour lequel il alloue de la mémoire.
  • Votre code est plus robuste et moins sujet aux erreurs manuelles.

En général, c'est toujours une bonne pratique de ne pas s'appuyer sur des types concrets et le premier formulaire ne fait que cela, il ne code pas en dur un type.

19
Alok Save

C'est pratique, car vous pouvez convertir ceci:

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

En cela:

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

struct node *p;
MALLOC(p);

Ou, pour un tableau:

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

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

Et pourquoi est-ce sûr? Parce que l'utilisateur qui utilise ces macros serait moins susceptible de faire des erreurs qui ont été décrites par AndreyT, tout comme dans le cas de DIM() pour obtenir la taille d'un tableau statique.

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

Ceci est également plus sûr, car l'utilisateur n'a pas besoin de rendre la taille du tableau statique cohérente à plusieurs endroits. Définissez la taille du tableau en un seul endroit, puis utilisez simplement la fonction DIM() et vous avez terminé! Le compilateur s'en charge pour vous.

4
ruben2020

Cela n'affecte pas directement la sécurité, mais on peut affirmer que cela peut empêcher un bug dans les futures révisions. D'un autre côté, il est facile d'oublier que le petit *. Que diriez-vous d'en faire un type, il est certainement plus propre.

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

Ensuite, vous pouvez le faire:

node_t *p = malloc(sizeof(node_t));
0
dashesy