Malheureusement, le littéral pointeur nul est l'une des parties confuses du langage. Laissez-moi essayer de récapituler :
-
Pour tout type, il existe le concept de "pointeur vers ce type". Par exemple, vous pouvez avoir des entiers et des pointeurs vers des entiers (int x; int *y;
), des doubles et des pointeurs vers des doubles (double x; double *y;
), Person et pointeur vers Person (Person x,*y;
). Si X
est un type alors "pointeur vers X" est un type en soi et donc vous pouvez même trouver des pointeurs vers des pointeurs vers des entiers (int **x;
) ou des pointeurs vers des pointeurs vers des pointeurs vers des caractères (char ***x;
).
-
Pour tout type de pointeur, il y a une valeur de pointeur nul
. C'est une valeur qui ne pointe pas réellement vers un objet, il est donc incorrect d'essayer de le déréférencer ("déréférencer" un pointeur signifie lire ou écrire l'objet vers lequel il pointe). Notez que le langage C++ ne garantit pas que vous obtiendrez un message d'erreur ou un plantage lorsque vous utilisez un pointeur nul pour accéder à un objet pointé qui n'existe pas, mais simplement que vous ne devriez pas le faire dans un programme car les conséquences sont imprévisibles. Le langage suppose simplement que vous ne ferez pas ce genre d'erreur.
* Comment le pointeur nul est-il exprimé dans un programme ? Voici la partie difficile. Pour des raisons qui dépassent l'entendement, le langage C++ utilise une règle étrange : si vous obtenez n'importe quelle expression entière constante avec une valeur nulle alors cela peut être (si nécessaire) considéré comme un pointeur nul pour n'importe quel type.
**
La dernière règle est extrêmement étrange et illogique et signifie par exemple que
char *x = 0; // x est un pointeur vers un caractère avec la valeur de pointeur nul (ok)
char *y = (1-1); // exactement la même chose (quoi ??)
char *z = !! !! !! !! !! !!
!!! !! !! !! !! !!
!!!! !! !! !! !! !!
!! !! !! !! !! !! !!
!! !!!! !! !! !! !!
!! !!! !! !! !! !!
!! !! !!!!!! !!!!!!! !!!!!!1; // Encore pareil (!)
et c'est vrai pour tout type de pointeur.
Pourquoi le standard exige-t-il que n'importe quelle expression et pas seulement un littéral zéro peut être considérée comme la valeur de pointeur nul ? Vraiment aucune idée.
Apparemment, Stroustrup a également trouvé la chose amusante au lieu d'être dégoûtant comme il se doit (le dernier exemple avec le texte "NULL" écrit avec un nombre impair de négations est présent dans le livre "The C++ Programming Language").
Remarquez également qu'il existe un symbole NULL
défini dans les en-têtes standard qui fournit une définition valide pour une valeur de pointeur nul pour tout type. En "C", une définition valide aurait pu être (void *)0
mais ce n'est pas valide en C++ car les pointeurs void ne peuvent pas être convertis implicitement en d'autres types de pointeurs comme c'est le cas en "C".
Remarquez également que vous pouvez trouver dans la littérature le terme NUL
(avec un seul L) mais c'est le caractère ASCII avec le code 0 (représenté en C/C++ avec '\0'
) et c'est une chose logiquement distincte d'un pointeur ou d'un nombre entier.
Malheureusement, en C++ les caractères sont aussi des entiers et donc par exemple '\0'
est une valeur de pointeur nulle valide et il en va de même pour ('A'-'A')
(ce sont des expressions constantes entières évaluant à zéro).
C++11 augmente la complexité de ces règles déjà douteuses avec std::nullptr_t
et nullptr
. Je ne peux pas expliquer ces règles car je ne les ai pas comprises moi-même (et je ne suis pas encore sûr à 100% de vouloir les comprendre).
**