Les adresses sont des nombres. Vous connaissez plusieurs types permettant de stocker des nombres :
int,
unsigned int,
double. Peut-on donc stocker une adresse dans une variable ?
La réponse est "oui". C'est possible. Mais pas avec les types que vous connaissez. Il nous faut utiliser un type un peu particulier : le
pointeur.
Un pointeur est une variable qui contient l'adresse d'une autre variable.
Retenez bien cette phrase. Elle peut vous sauver la vie dans les moments les plus difficiles de ce chapitre.
Déclarer un pointeur
Pour déclarer un pointeur, il faut, comme pour les variables, deux choses :
Pour le nom, il n'y a rien de particulier à signaler. Les mêmes règles que pour les variables s'appliquent. Ouf !
Le type d'un pointeur a une petite subtilité. Il faut indiquer quel est le type de variable dont on veut stocker l'adresse et ajouter une étoile (
*).

Je crois qu'un exemple sera plus simple.
Code : C++ - Déclaration d'un pointeur
Ce code déclare un pointeur qui peut contenir l'adresse d'une variable de type
int.
On peut également écrire int* pointeur (l'étoile collée au mot int).
Cette notation a un léger désavantage, c'est qu'on ne peut pas déclarer plusieurs pointeurs sur la même ligne comme ceci : int* pointeur1, pointeur2, pointeur3;. En faisant ça, seul pointeur1 sera un pointeur, les deux autres variables seront des entiers tout à fait standards.
On peut bien sûr faire ça pour n'importe quel type :
Code : C++ - Déclaration de pointeurs | double *pointeurA; //Un pointeur qui peut contenir l'adresse d'un nombre a virgule
unsigned int *pointeurB; //Un pointeur qui peut contenir l'adresse d'un nombre entier positif
string *pointeurC; //Un pointeur qui peut contenir l'adresse d'une chaîne de caractères
vector<int> *pointeurD; //Un pointeur qui peut contenir l'adresse d'un tableau dynamique de nombres entiers
int const *pointeurE; //Un pointeur qui peut contenir l'adresse d'un nombre entier constant
|
Pour le moment, ces pointeurs ne contiennent aucune adresse connue. C'est une situation très dangereuse. Si vous essayez d'utiliser le pointeur, vous ne savez pas quelle case de la mémoire vous manipulez. Ca peut être n'importe laquelle, par exemple la case qui contient votre mot de passe Windows ou la case qui contient l'heure actuelle. J'imagine que vous vous rendez compte des conséquences que peut avoir une mauvaise manipulation des pointeurs. Il ne faut donc
JAMAIS déclarer un pointeur sans lui donner d'adresse.
Il faut donc toujours déclarer un pointeur en lui donnant la valeur 0 pour être tranquille :
Code : C++ - Déclaration d'un pointeur | int *pointeur(0);
double *pointeurA(0);
unsigned int *pointeurB(0);
string *pointeurC(0);
vector<int> *pointeurD(0);
int const *pointeurE(0);
|
Vous l'avez peut-être remarqué sur mon schéma un peu plus tôt, la première case de la mémoire avait l'adresse 1. En effet, l'adresse 0 n'existe pas.
Lorsque vous créez un pointeur contenant l'adresse 0, cela signifie qu'il ne contient l'adresse d'
aucune case.
Je me répète, mais c'est très important : déclarez toujours vos pointeurs en les initialisant à l'adresse 0.
Stocker une adresse
Maintenant qu'on a la variable, il n'y a plus qu'à mettre une valeur dedans. Vous savez déjà comment obtenir l'adresse d'une variable (rappelez-vous du
&). Allons-y !
Code : C++ | int main()
{
int ageUtilisateur(16); //Une variable de type int.
int *ptr(0); //Un pointeur pouvant contenir l'adresse d'un nombre entier.
ptr = &ageUtilisateur; //On met l'adresse de 'ageUtilisateur' dans le pointeur 'ptr'.
return 0;
}
|
La ligne 6 est celle qui nous intéresse. Elle écrit l'adresse de la variable
ageUtilisateur dans le pointeur
ptr. On dit alors que le pointeur
ptr pointe sur ageUtilisateur.
Voyons comment tout cela se déroule dans la mémoire avec un ... schéma !
On retrouve quelques éléments familiers. La mémoire avec sa grille de cases et la variable
ageUtilisateur dans la case n°53768.
La nouveauté est bien sûr le pointeur. Dans la case mémoire n°14566, il y a une variable nommée
ptr qui a pour valeur l'adresse 53768, c'est-à-dire l'adresse de la variable
ageUtilisateur.
Voilà. Vous savez tout ou presque. Cela peut sembler absurde pour le moment ("Pourquoi stocker l'adresse d'une variable dans une autre case ?"), mais faites-moi confiance les choses vont progressivement s'éclairer pour vous.
Si vous avez compris le schéma précédent, alors vous pouvez vous attaquer aux programmes les plus complexes.
Afficher l'adresse
Comme pour toutes les variables, on peut afficher le contenu d'un pointeur.
Code : C++ 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 | #include <iostream>
using namespace std;
int main()
{
int ageUtilisateur(16);
int *ptr(0);
ptr = &ageUtilisateur;
cout << "L'adresse de 'ageUtilisateur' est : " << &ageUtilisateur << endl;
cout << "La valeur de pointeur est : " << ptr << endl;
return 0;
}
|
Ce qui donne :
Code : Console | L'adresse de 'ageUtilisateur' est : 0x2ff18
La valeur de pointeur est : 0x2ff18 |
La valeur du pointeur est donc bien l'adresse de la variable pointée. On a bien réussi à stocker une adresse !
Accéder à la valeur pointée
Vous vous souvenez du but des pointeurs ? Accéder à une variable sans passer par son nom. Voici comment faire. Il faut utiliser l'étoile (
*) sur le pointeur pour afficher la valeur de la variable pointée.
Code : C++ | int main()
{
int ageUtilisateur(16);
int *ptr(0);
ptr= &ageUtilisateur;
cout << "La valeur est : " << *ptr << endl;
return 0;
}
|
En faisant
cout << *ptr, le programme va effectuer les étapes suivantes :
- Aller dans la case mémoire nommée ptr.
- Lire la valeur enregistrée.
- "Suivre la flèche" pour aller à l'adresse pointée.
- Lire la valeur stockée dans la case.
- Afficher cette valeur. Ici, ce sera bien sûr 16 qui sera affiché.
En utilisant l'étoile, on accède à la
valeur de la variable pointée. C'est ce qui s'appelle
déréférencer un pointeur.
Voici donc un deuxième moyen d'accéder à la valeur de
ageUtilisateur.
Mais, à quoi cela sert-il ?
Je suis sûr que vous vous êtes retenu de poser la question avant.

C'est vrai que ça a l'air assez inutile. Eh bien, je ne peux pas vous répondre rapidement pour le moment.
Il va falloir lire la fin de ce chapitre pour tout savoir.
Récapitulatif de la notation
Je suis d'accord avec vous, la notation est compliquée. L'étoile a deux significations différentes et on utilise l'esperluette alors qu'elle est déjà utilisée pour les références... Ce n'est pas ma faute ! Si vous voulez vous plaindre, il faut voir du côté des concepteurs du langage. C'est eux les responsables de ce charabia.
Nous, on ne peut que faire avec. Essayons donc de récapituler le tout.
Pour une variable
int nombre :
- nombre permet d'accéder à la valeur de la variable.
- &nombre permet d'accéder à l' adresse de la variable.
Sur un pointeur
int *pointeur :
- pointeur permet d'accéder à la valeur du pointeur, c'est-à-dire à l'adresse de la variable pointée.
- *pointeur permet d'accéder à la valeur de la variable pointée.
C'est ce qu'il faut retenir de cette sous-partie. Je vous invite à tester tout ça chez vous pour bien vérifier que vous avez compris comment afficher une adresse, comment utiliser un pointeur, etc.
"C'est en forgeant qu'on devient forgeron" dit le dicton, eh bien c'est en programmant avec des pointeurs que l'on devient programmeur. Il faut impérativement s'entraîner pour bien comprendre. Les meilleurs sont tous passés par là et je peux vous assurer qu'ils ont aussi souffert en découvrant les pointeurs. Si vous ressentez une petite douleur dans la tête, prenez un cachet d'aspirine, faites une pause, puis relisez ce que vous venez de lire encore et encore. Aidez-vous en particulier des schémas !
