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.
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.
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:
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.
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.
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));