La détermination du type d'une variable à partir de sa déclaration peut parfois s'avérer délicate en C et C++, surtout lorsqu'elle implique des pointeurs, des tableaux et des combinaisons des deux. Une règle de lecture systématique permet de déchiffrer ces syntaxes, souvent perçues comme intimidantes.
La règle fondamentale : Lecture de droite à gauche Lorsqu'une déclaration de varible ne contient pas de parenthèses, le type est déterminé en lisant la déclaration de droite à gauche, en partant du nom de la variable. Le premier qualificateur rencontré en allant vers la gauche définit la nature immédiate de la variable.
Considérons quelques exemples basiques :
int val_simple; // Lisez : "val_simple est un int"
char *ptr_char; // Lisez : "ptr_char est un pointeur (à droite de *), vers un char (à gauche)"
double **ptr_sur_ptr_double; // Lisez : "ptr_sur_ptr_double est un pointeur (à droite de *), vers un pointeur (à gauche du premier *), vers un double (encore à gauche)"
Cette règle s'applique également aux tableaux. La déclaration int tableau[10]; se lit "tableau est un tableau de 10 éléments, ces éléments sont des int".
Un point de confusion courant est la distinction entre un tableau de pointeurs et un pointeur vers un tableau. Prenons le cas de char *liste_noms[5]; : En lisant de droite à gauche, le premier qualificateur après liste_noms est [5]. Cela signifie que liste_noms est un tableau de 5 éléments. Ensuite, en allant vers la gauche, nous trouvons *, puis char. Donc, liste_noms est un "tableau de 5 éléments, où chaque élément est un pointeur vers un char". Il s'agit d'un tableau de chaînes de caractères.
Pour déclarer un pointeur vers un tableau (et non un tableau de pointeurs), les parenthèses sont essentielles :
int (*ptr_vers_tableau)[15]; // Correct : un pointeur vers un tableau de 15 entiers
Ici, les parenthèses (*ptr_vers_tableau) sont lues en premier. Cela indique que ptr_vers_tableau est un pointeur. Après avoir traité le contenu des parenthèses, la lecture se poursuit à l'extérieur vers la droite, où nous voyons [15], puis vers la gauche avec int. Ainsi, ptr_vers_tableau est un "pointeur vers un tableau de 15 entiers".
long *(*ptr_tab_long_ptr)[7];
ptr_tab_long_ptr(variable principale).- Priorité aux parenthèses :
(*ptr_tab_long_ptr)indique queptr_tab_long_ptrest un pointeur. - En dehors des parenthèses, à droite :
[7]signifie qu'il pointe vers un tableau de 7 éléments. - À gauche de l'astérisque de la parenthèse :
long *indique que les éléments du tableau sont des pointeurs vers deslong. Conclusion :ptr_tab_long_ptrest un pointeur vers un tableau de 7 pointeurs vers deslong.
Un autre exemple plus avancé :
float (*(*ptr_vers_matrice))[3][4];
ptr_vers_matrice(variable principale).- Parenthèses intérieures :
(*ptr_vers_matrice)indique queptr_vers_matriceest un pointeur. - Parenthèses extérieures :
(*...)indique que ce que pointeptr_vers_matriceest également un pointeur. - À droite de la parenthèse extérieure :
[3][4]signifie qu'il pointe vers un tableau 3x4 (une matrice). - À gauche du type principal :
floatindique que les éléments de cette matrice sont desfloat. Conclusion :ptr_vers_matriceest un pointeur vers un pointeur qui lui-même pointe vers une matrice defloatde dimensions 3x4.
En récapitulatif, la règle "lecture de droite à gauche, avec priorité aux parenthèses" est un outil puissant pour décoder les déclarations de types les plus complexes en C et C++.