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

Donné

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

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 qu’ils sont les mêmes.

Il est plus sûr de ne pas avoir à mentionner le nom du type deux fois et de ne pas avoir à créer l’orthographe appropriée pour la version “déréférencée” du type. Par exemple, vous n’avez pas à “compter les écanvass” dans

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

Comparez cela à la sizeof basée sur le type dans

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

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

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

Plus généralement, il est logique de suivre les directives suivantes: les noms de types appartiennent aux déclarations et nulle part ailleurs. Les instructions réelles doivent être indépendantes du type. Ils devraient éviter de mentionner des noms de type ou d’utiliser autant que possible d’autres fonctionnalités spécifiques à un type.

Ce dernier terme signifie: éviter les moulages inutiles. Évitez la syntaxe constante spécifique au type (comme 0.0 ou 0L où un simple 0 suffirait). Évitez de mentionner les noms de type sous sizeof . Etc.

Parce que si à un moment donné p est amené à pointer vers un autre type de structure, votre instruction d’allocation de mémoire utilisant malloc n’a pas à changer, elle alloue toujours assez de mémoire pour le nouveau type . Il assure:

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

En général, il est toujours bon de ne pas utiliser des types concrets et la première forme ne fait que cela, elle ne code pas un type.

C’est pratique, car vous pouvez convertir ceci:

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

Dans ceci:

 #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 est moins susceptible de commettre des erreurs décrites par AndreyT, comme dans le cas de DIM() pour obtenir la taille d’un tableau statique.

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

Cela 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 à un endroit, puis utilisez simplement le DIM() et vous avez terminé! Le compilateur s’en charge pour vous.

Cela n’affecte pas directement la sécurité, mais on peut affirmer que cela peut empêcher un bug dans les révisions futures. D’un autre côté, il est facile d’oublier ce petit * . Que diriez-vous 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));