Un pointeur contient une adresse
Un pointeur, en langage C, est une variable qui contient l’adresse d’une autre variable. Lire du code C sans comprendre les pointeurs est impossible, car presque toutes les fonctions de la bibliothèque en reçoivent.
Une bibliothèque municipale note, pour chaque livre, le numéro de son étagère plutôt que le livre lui-même. Le pointeur joue ce rôle : on le suit pour trouver la valeur.
À la fin de cette leçon
Remarque
Je peux lire et écrire du code C qui utilise des pointeurs.
Mots-clés
| Mot | Ce que ça veut dire | Exemple |
|---|---|---|
| Pointeur | une variable qui contient une adresse | int *p |
| Adresse de | l’opérateur & donne l’adresse d’une variable | &x |
| Déréférencement | l’opérateur * va lire ou écrire à l’adresse | *p |
| Arithmétique de pointeurs | p + 1 avance d’un élément entier | |
| NULL | l’adresse spéciale qui ne désigne aucune variable |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Le signe & donne l’adresse, le signe * la suit
Écrire &x donne l’adresse de la variable x. Écrire int *p déclare un pointeur p vers un int. Le signe * devant un pointeur, comme dans *p, va à l’adresse et lit ou écrit la valeur qui s’y trouve.
Après p = &x, écrire *p = 9 change x lui-même. Il n’y a qu’une seule valeur, avec deux façons de l’atteindre.
Pointeurs vers un entier et un tableau
int x = 7;
int *p = &x;
*p = 9;
int t[4] = {10, 20, 30, 40};
int *q = t;Aller dans le dossier de travail
mkdir -p ~/c && cd ~/cAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Écrire le programme dans un fichier
printf '#include <stdio.h>\nint main(void) {\n int x = 7;\n int *p = &x;\n *p = 9;\n printf("%%d\\n", x);\n int t[4] = {10, 20, 30, 40};\n int *q = t;\n printf("%%d %%d\\n", *(q + 1), q[2]);\n printf("%%ld\\n", (long)((q + 3) - q));\n printf("%%ld\\n", (long)((char *)(q + 3) - (char *)q));\n return 0;\n}\n' > pointeurs.cAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Compiler et lancer le programme
gcc -Wall -o pointeurs pointeurs.c && ./pointeursAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
p + 1 saute un élément, pas un octet
Un pointeur vers un int avance par pas de quatre octets, la taille d’un int. Le compilateur multiplie pour vous : q + 3 est l’adresse de départ plus 3 fois 4. Et q[2] s’écrit aussi *(q + 2).
Le programme a affiché 3 pour (q + 3) - q, une distance en éléments, puis 12 une fois les deux pointeurs convertis en pointeurs d’octets.
Exemple travaillé : un tableau de quatre entiers
| Expression | Décalage en octets | Valeur lue |
|---|---|---|
| *q ou q[0] | 0 | 10 |
| *(q + 1) | 4 | 20 |
| q[2] | 8 | 30 |
| *(q + 3) | 12 | 40 |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Une fonction modifie une variable par adresse
En C, une fonction reçoit une copie de chaque argument. Pour qu’elle change la variable de l’appelant, on lui passe l’adresse de cette variable.
La fonction echanger reçoit deux pointeurs et échange les deux valeurs. L’appel echanger(&a, &b) change vraiment a et b, sans rien retourner.
Échanger deux entiers par leurs adresses
void echanger(int *a, int *b) {
int reserve = *a;
*a = *b;
*b = reserve;
}Écrire le programme d’échange
printf '#include <stdio.h>\nvoid echanger(int *a, int *b) {\n int reserve = *a;\n *a = *b;\n *b = reserve;\n}\nint main(void) {\n int x = 1;\n int y = 2;\n echanger(&x, &y);\n printf("%%d %%d\\n", x, y);\n return 0;\n}\n' > echange.cAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Compiler et lancer l’échange
gcc -Wall -o echange echange.c && ./echangeAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Erreur fréquente
Attention
Beaucoup de gens pensent qu’un pointeur déclaré contient déjà une adresse utilisable. Un pointeur sans valeur désigne n’importe quoi, et NULL ne désigne rien. Suivre l’un ou l’autre fait planter le programme. Donnez toujours une adresse valide à un pointeur avant d’écrire *p.