Un pointeur contient une valeur qui permet de désigner un objet, ou une valeur nulle qui ne désigne aucun objet. Comprendre les pointeurs commence par séparer la variable, son adresse et la valeur stockée à cette adresse.
Adresse et indirection
Si int n=5;, &n fournit l’adresse de n. La déclaration int *p=&n; crée un pointeur vers int. L’expression *p accède alors à l’objet désigné. Affecter *p=8; modifie n ; affecter une autre adresse à p change ce que p désigne. Ces deux affectations ne font donc pas la même chose.
Un pointeur doit être valide
Un pointeur local non initialisé n’est pas une adresse utilisable. NULL représente une valeur de pointeur nul ; il faut la tester avant toute indirection. Un objet automatique cesse d’exister à la sortie de sa portée : renvoyer son adresse depuis une fonction ne prolonge pas sa vie. La validité ne dépend pas seulement de la présence d’une valeur non nulle.
Fonctions et adresses
Le passage reste par valeur : une fonction reçoit une copie du pointeur. Mais cette copie désigne le même objet, donc une affectation à travers le pointeur peut modifier l’objet de l’appelant. Pour changer la valeur du pointeur lui-même chez l’appelant, un autre niveau d’indirection ou un résultat de fonction est nécessaire. Ne pas dire que tous les paramètres C seraient soudain passés par référence.
Tableaux et arithmétique
Dans beaucoup d’expressions, un tableau fournit un pointeur vers son premier élément. À l’intérieur d’un même tableau, avancer un pointeur d’un élément tient compte de la taille du type pointé. Un pointeur juste après le dernier élément peut servir de borne, mais ne doit pas être déréférencé. L’arithmétique entre objets sans relation n’est pas un moyen valide de parcourir la mémoire.
const et affichage
const int *p interdit de modifier l’entier à travers p ; int * const p interdit de réaffecter le pointeur. Les deux propriétés sont différentes. Pour afficher une adresse avec printf, le format est %p et l’argument doit être converti en void*. La représentation dépend de l’exécution ; un cours ne doit pas annoncer une adresse numérique fixe comme résultat portable.
Le pointeur et l’entier désigné sont deux objets distincts.
Pointeurs : changer une valeur via son adresse
#include <stdio.h>
void ajouter_un(int *p) {
if (p != NULL) { ++(*p); }
}
int main(void) {
int n = 5;
int *p = &n;
*p = 8;
ajouter_un(p);
printf("n = %d\n", n);
printf("*p = %d\n", *p);
return 0;
}
Suivre le programme : Pointeurs, changer une valeur via son adresse
Instruction ou étape
Explication
p=&n
p désigne l’objet n, pas une copie de sa valeur.
*p=8
Le contenu de n devient 8.
ajouter_un(p)
La fonction reçoit l’adresse ; ++(*p) fait passer n à 9.
Deux affichages
n et *p accèdent au même entier et valent donc 9.
Sortie écran : essai 1
Le pointeur et son objet restent valides pendant main.
n = 9
*p = 9
Pointeurs : échanger deux objets
#include <stdio.h>
void echanger(int *a, int *b) {
if (a == NULL || b == NULL) { return; }
int temporaire = *a;
*a = *b;
*b = temporaire;
}
int main(void) {
int x = 3, y = 8;
echanger(&x, &y);
printf("x = %d, y = %d\n", x, y);
return 0;
}
Suivre le programme : Pointeurs, échanger deux objets
Instruction ou étape
Explication
&x et &y
Les deux adresses permettent de modifier les deux objets.
temporaire=*a
Sauvegarde 3 avant d’écraser x.
*a=*b puis *b=temporaire
x devient 8, puis y devient 3.
Gardes NULL
Évitent une indirection nulle si l’appelant transmet NULL.
Sortie écran : essai 1
Les paramètres sont des copies d’adresses, mais désignent x et y.
x = 8, y = 3
S’entraîner et vérifier
Exercice 1. Quelle différence entre p=&n et *p=n ?
Voir la correctionMasquer la correction
La première instruction change l’adresse stockée dans p. La seconde copie la valeur de n dans l’objet déjà désigné par p, qui doit être valide.
Exercice 2. Pourquoi ++(*p) plutôt que *p++ pour augmenter l’entier ?
Voir la correctionMasquer la correction
Les parenthèses désignent clairement l’objet à incrémenter. Sans elles, le post-incrément porte sur le pointeur p ; l’expression ne réalise pas la même action.
Repère de lecture : les codes proposés utilisent des constructions disponibles en C11. Les règles du langage et de sa bibliothèque sont consultables dans les projets publics du WG14 (C11) et du WG14 (C23). Les exemples n’utilisent pas les nouveautés propres à C23.
Questions / Réponses
Aucune question. Soyez le premier à poser une question.