Est-il nécessaire d’appeler pointeur = NULL lors de l’initialisation?

lorsque je crée un pointeur sur une certaine structure, dois-je le définir sur NULL, puis l’allouer puis l’utiliser? et pourquoi?

Non, il n’y a aucune exigence (en ce qui concerne la langue) pour initialiser une variable de pointeur à quoi que ce soit lors de sa déclaration. Ainsi

T* ptr; 

est une déclaration valide qui introduit une variable nommée ptr avec une valeur indéterminée. Vous pouvez même utiliser la variable de certaines manières sans rien allouer au préalable ni lui atsortingbuer une valeur spécifique:

 func(&ptr); 

Non, vous n’avez pas besoin de le définir sur NULL , mais certains considèrent que c’est une bonne pratique, car cela donne à un nouveau pointeur une valeur qui le rend explicite, il ne pointe pas (encore) sur rien.

Si vous créez un pointeur et que vous lui affectez immédiatement une autre valeur, le réglage sur NULL n’a pas beaucoup de valeur.

Il est toutefois judicieux de définir un pointeur sur NULL après avoir libéré la mémoire vers laquelle il pointe.

Non, n’oubliez pas que l’initialisation doit être un pointeur null. Un langage très pratique en C moderne consiste à déclarer des variables lors de leur première utilisation

 T * ptr = malloc(sizeof *ptr); 

Cela vous évite beaucoup de remue-ménage sur le type et sur le fait qu’une variable est déjà initialisée ou non. Si vous ne savez pas où (ou même si) il est initialisé plus tard, vous devriez l’initialiser définitivement à un pointeur nul.

En règle générale, initialisez toujours les variables à la valeur appropriée. Le “bon 0 pour le type” est toujours un bon choix si vous n’en avez pas un meilleur sous la main. Pour tous les types, C est fait comme ça, de sorte que cela fonctionne.

Ne pas initialiser une variable est une optimisation prématurée dans la plupart des cas. Examinez vos variables uniquement lorsque vous constatez un réel goulot d’étranglement au niveau des performances. En particulier, s’il existe une affectation dans la même fonction avant l’utilisation de la valeur initiale, le compilateur moderne vous optimisera l’initialisation. Pensez d’abord à l’exactitude de votre programme.

Selon la norme C, ne pas initialiser une variable de stockage automatique laisse sa valeur indéterminée.

Vous êtes certainement encouragé à définir les pointeurs sur NULL chaque fois que l’alternative est que votre pointeur ait une valeur indéterminée. L’utilisation de pointeurs avec une valeur indéterminée est un comportement indéfini , un concept que vous pourriez ne pas comprendre correctement si vous êtes habitué à la programmation en C et que vous venez de langages de niveau supérieur.

Un comportement indéfini signifie que tout peut arriver , et cela fait partie du standard C puisque la philosophie du C laisse le programmeur avoir le fardeau de contrôler les choses au lieu de le protéger de ses erreurs.

Vous voulez éviter des comportements indéfinis dans le code: il est très difficile de déboguer des choses lorsqu’un comportement quelconque peut se produire. Il n’est pas attrapé par un compilateur, et vos tests peuvent toujours passer, laissant le bug inaperçu jusqu’à ce qu’il soit très coûteux de le corriger.

Si vous faites quelque chose comme ça:

 char *p; if(!p) puts("Pointer is NULL"); 

Vous ne savez pas réellement if contrôle sera vrai ou faux. Ceci est extrêmement dangereux dans les grands programmes où vous pouvez déclarer votre variable puis l’utiliser quelque part très loin dans l’espace et dans le temps.

Même concept lorsque vous référencez de la mémoire libérée.

 free(p); printf("%s\n", p); p = q; 

Vous ne savez pas vraiment ce que vous allez obtenir avec les deux dernières déclarations. Vous ne pouvez pas le tester correctement, vous ne pouvez pas être sûr de votre résultat. Votre code peut sembler fonctionner, car la mémoire libérée est recyclée, même si elle a peut-être été modifiée … vous pouvez même écraser la mémoire ou corrompre d’autres variables partageant la même mémoire. Donc, vous avez toujours un bogue qui se manifestera tôt ou tard et qui pourrait être très difficile à déboguer.

Si vous définissez le pointeur sur NULL, vous vous protégez de ces situations dangereuses: lors de vos tests, votre programme aura un comportement déterministe et prévisible qui échouera rapidement et à moindre coût. Vous obtenez une erreur de segmentation, vous attrapez le bogue, vous corrigez le bogue. Propre et simple:

 #include  #include  int main(){ char* q; if(!q) puts("This may or may not happen, who knows"); q = malloc(10); free(q); printf("%s\n", q); // this is probably don't going to crash, but you still have a bug char* p = NULL; if(!p) puts("This is always going to happen"); p = malloc(10); free(p); p = NULL; printf("%s\n", p); // this is always going to crash return 0; } 

Ainsi, lorsque vous initialisez un pointeur, en particulier dans les grands programmes, vous souhaitez qu’il soit explicitement initialisé ou défini sur NULL. Vous ne voulez pas qu’ils obtiennent une valeur indéterminée, jamais. Je devrais dire à moins que vous ne sachiez ce que vous faites , mais je préfère ne jamais le faire .

Vous n’êtes pas obligé de le faire sauf si vous ne le souhaitez pas. Vous savez que vous devriez après avoir libéré (style défensif).

Vous n’êtes pas obligé d’initialiser à NULL. Si vous avez l’intention de l’affecter immédiatement, vous pouvez le sauter.

At peut être utile pour la gestion des erreurs, comme dans l’exemple suivant. Dans ce cas, interrompre jusqu’au bout après l’allocation p laisserait q non initialisé.

 int func(void) { char *p; char *q; p = malloc(100); if (!p) goto end; q = malloc(100); if (!q) goto end; /* Do something */ end: free(p); free(q); return 0; } 

De plus, et c’est mon goût personnel, calloc structures toujours avec calloc . Les chaînes peuvent être allouées sans initialisation avec malloc