Utiliser des pointeurs 




Jusqu'ici, nous avons uniquement créé des variables faites pour contenir des nombres. Maintenant, nous allons apprendre à créer des variables faites pour contenir des adresses : ce sont justement ce qu'on appelle des pointeurs.

Mais… Les adresses sont des nombres aussi, non ? Ça revient à stocker des nombres encore et toujours !



C'est exact. Mais ces nombres auront une signification particulière : ils indiqueront l'adresse d'une autre variable en mémoire.

Créer un pointeur



Pour créer une variable de type pointeur, on doit rajouter le symbole * devant le nom de la variable.

int *monPointeur;


Notez qu'on peut aussi écrire int* monPointeur;. Cela revient exactement au même. Cependant, la première méthode est à préférer. En effet, si vous voulez déclarer plusieurs pointeurs sur la même ligne, vous serez obligés de mettre l'étoile devant le nom : int *pointeur1, *pointeur2, *pointeur3;.



Comme je vous l'ai appris, il est important d'initialiser dès le début ses variables, en leur donnant la valeur 0 par exemple. C'est encore plus important de le faire avec les pointeurs !
Pour initialiser un pointeur, c'est-à-dire lui donner une valeur par défaut, on n'utilise généralement pas le nombre 0 mais le mot-clé NULL (veillez à l'écrire en majuscules) :

int *monPointeur = NULL;



Là, vous avez un pointeur initialisé à NULL. Comme ça, vous saurez dans la suite de votre programme que votre pointeur ne contient aucune adresse.

Que se passe-t-il ? Ce code va réserver une case en mémoire comme si vous aviez créé une variable normale. Cependant, et c'est ce qui change, la valeur du pointeur est faite pour contenir une adresse. L'adresse… d'une autre variable.

Pourquoi pas l'adresse de la variable age ? Vous savez maintenant comment indiquer l'adresse d'une variable au lieu de sa valeur (en utilisant le symbole &), alors allons-y ! Ça nous donne :

int age = 10;

int *pointeurSurAge = &age;



La première ligne signifie : « Créer une variable de type int dont la valeur vaut 10 ». La seconde ligne signifie : « Créer une variable de type pointeur dont la valeur vaut l'adresse de la variable age ».

La seconde ligne fait donc deux choses à la fois. Si vous le souhaitez, pour ne pas tout mélanger, sachez qu'on peut la découper en deux temps :

int age = 10;

int *pointeurSurAge; // 1) signifie "Je crée un pointeur"

pointeurSurAge = &age; // 2) signifie "pointeurSurAge contient l'adresse de la variable age"



Vous avez remarqué qu'il n'y a pas de type « pointeur » comme il y a un type int et un type double. On n'écrit donc pas :

pointeur pointeurSurAge;



Au lieu de ça, on utilise le symbole *, mais on continue à écrire int. Qu'est-ce que ça signifie ? En fait, on doit indiquer quel est le type de la variable dont le pointeur va contenir l'adresse. Comme notre pointeur pointeurSurAge va contenir l'adresse de la variable age (qui est de type int), alors mon pointeur doit être de type int* ! Si ma variable age avait été de type double, alors j'aurais dû écrire double *monPointeur.

Vocabulaire : on dit que le pointeur pointeurSurAge pointe sur la variable age.

La fig. suivante résume ce qu'il s'est passé dans la mémoire.



Dans ce schéma, la variable age a été placée à l'adresse 177450 (vous voyez d'ailleurs que sa valeur est 10), et le pointeur pointeurSurAge a été placé à l'adresse 3 (c'est tout à fait le fruit du hasard).

Lorsque mon pointeur est créé, le système d'exploitation réserve une case en mémoire comme il l'a fait pour age. La différence ici, c'est que la valeur de pointeurSurAge est un peu particulière. Regardez bien le schéma : c'est l'adresse de la variable age !

Ceci, chers lecteurs, est le secret absolu de tout programme écrit en langage C. On y est, nous venons de rentrer dans le monde merveilleux des pointeurs !

Et… ça sert à quoi ?



Ça ne transforme pas encore votre ordinateur en machine à café, certes. Seulement maintenant, on a un pointeurSurAge qui contient l'adresse de la variable age.


Essayons de voir ce que contient le pointeur à l'aide d'un printf :

int age = 10;

int *pointeurSurAge = &age;


printf("%d", pointeurSurAge);




177450




Hum. En fait, cela n'est pas très étonnant. On demande la valeur de pointeurSurAge, et sa valeur c'est l'adresse de la variable age (177450).


Comment faire pour demander à avoir la valeur de la variable se trouvant à l'adresse indiquée dans pointeurSurAge ? Il faut placer le symbole * devant le nom du pointeur :

int age = 10;

int *pointeurSurAge = &age;


printf("%d", *pointeurSurAge);




10




Hourra ! Nous y sommes arrivés ! En plaçant le symbole * devant le nom du pointeur, on accède à la valeur de la variable age.

Si au contraire on avait utilisé le symbole & devant le nom du pointeur, on aurait obtenu l'adresse à laquelle se trouve le pointeur (ici, c'est 3).

Qu'est-ce qu'on y gagne ? On a simplement réussi à compliquer les choses ici. On n'avait pas besoin d'un pointeur pour afficher la valeur de la variable age !



Cette question (que vous devez inévitablement vous poser) est légitime. Après tout, qui pourrait vous en vouloir ? Actuellement l'intérêt n'est pas évident, mais petit à petit, tout au long des chapitres suivants, vous comprendrez que tout cela n'a pas été inventé par pur plaisir de compliquer les choses.

Faites l'impasse sur la frustration que vous devez ressentir (« Tout ça pour ça ? »). Si vous avez compris le principe, c'est l'essentiel. Les choses s'éclairciront d'elles-mêmes par la suite.

À retenir absolument



Voici ce qu'il faut avoir compris et ce qu'il faut retenir pour la suite de ce chapitre :

  • sur une variable, comme la variable age :
    • age signifie : « Je veux la valeur de la variable age »,
    • &age signifie : « Je veux l'adresse à laquelle se trouve la variable age » ;
  • sur un pointeur, comme pointeurSurAge :
    • pointeurSurAge signifie : « Je veux la valeur de pointeurSurAge » (cette valeur étant une adresse),
    • *pointeurSurAge signifie : « Je veux la valeur de la variable qui se trouve à l'adresse contenue dans pointeurSurAge ».

Contentez-vous de bien retenir ces quatre points. Faites des tests et vérifiez que ça marche.
Le schéma de la fig. suivante devrait bien vous aider à situer chacun de ces éléments.


Attention à ne pas confondre les différentes significations de l'étoile ! Lorsque vous déclarez un pointeur, l'étoile sert juste à indiquer qu'on veut créer un pointeur : int *pointeurSurAge;.
En revanche, lorsqu'ensuite vous utilisez votre pointeur en écrivant printf("%d", *pointeurSurAge);, cela ne signifie pas « Je veux créer un pointeur » mais : « Je veux la valeur de la variable sur laquelle pointe mon pointeurSurAge ».



Tout cela est fon-da-men-tal. Il faut connaître cela par cœur et surtout le comprendre. N'hésitez pas à lire et relire ce qu'on vient d'apprendre. Je ne peux pas vous en vouloir si vous n'avez pas compris du premier coup et ce n'est pas une honte non plus, d'ailleurs. Il faut en général quelques jours pour bien comprendre et souvent quelques mois pour en saisir toutes les subtilités.

Si vous vous sentez un peu perdus, pensez à ces gens qui sont aujourd'hui de grands gourous de la programmation : aucun d'entre eux n'a compris tout le fonctionnement des pointeurs du premier coup. Et si jamais cette personne existe, il faudra vraiment me la présenter.    

Créé avec HelpNDoc Personal Edition: Générateur de documentation iPhone gratuit