Classe inversée : Pointeurs¶
1. Cours¶
En C, comprendre la mémoire est la clée. Jusqu'à présent, vous avez manipulé des variables et des tableaux. Observons une différence fondamentale entre les deux.
1. L'expérience¶
Copiez le code ci-dessous et essayez de prédire ce qu'il va afficher avant de l'exécuter.
include <stdio.h>
// Fonction qui tente de modifier un entier
void changer_entier(int x) {
x = 999;
printf("Dans la fonction changer_entier : x vaut %d\n", x);
}
// Fonction qui tente de modifier un tableau
void changer_tableau(int t[]) {
t[0] = 999;
printf("Dans la fonction changer_tableau : t[0] vaut %d\n", t[0]);
}
int main() {
int ma_variable = 10;
int mon_tableau[3] = {10, 20, 30};
printf("--- Test 1 : Variable ---\n");
printf("Avant : %d\n", ma_variable);
changer_entier(ma_variable);
printf("Après : %d <-- POURQUOI N'A-T-ELLE PAS CHANGE ?\n\n", ma_variable);
printf("--- Test 2 : Tableau ---\n");
printf("Avant : %d\n", mon_tableau[0]);
changer_tableau(mon_tableau);
printf("Après : %d <-- POURQUOI A-T-IL CHANGE ?\n", mon_tableau[0]);
return 0;
}
2. L'explication¶
Pourquoi cette différence ?
-
Variable simple (
int x) : Le photocopieur. Quand vous passezma_variableà la fonction, le C fait une COPIE de la valeur. La fonction travaille sur une feuille de papier différente. Si elle gribouille dessus (x = 999), votre feuille originale (ma_variabledans le main) reste intacte. C'est le "Passage par valeur". -
Tableau (
int t[]) : Le GPS. Un tableau est trop gros pour être copié entier. Quand vous passez un tableau, le C ne copie pas les valeurs. Il donne l'adresse mémoire du début du tableau (comme des coordonnées GPS). La fonction va donc modifier directement les cases à cette adresse précise. C'est le "Passage par adresse" (via un pointeur).
Pour modifier une variable simple à distance (comme on le fait pour le tableau), nous avons besoin d'un nouvel outil : Le Pointeur.
La mémoire, c'est comme une rue¶
Imaginez que la mémoire de votre ordinateur est une immense rue avec des boîtes aux lettres numérotées.
- L'Adresse : Le numéro de la boîte (ex: 1024).
- La Variable : Le contenu de la boîte (ex: 42).
Vision simplifiée de la mémoire :
| Adresse Mémoire | Nom Variable | Contenu (Valeur) | Commentaire |
|---|---|---|---|
| 0x7ffee4 | a | 10 | Notre entier |
| 0x7ffee8 | p | 0x7ffee4 | Le pointeur vers a |
Un pointeur est une variable qui contient l'ADRESSE d'une autre variable.
Au lieu de stocker la valeur "10", le pointeur p stocke "l'endroit où se trouve 10".
Les deux outils (Opérateurs)¶
Pour manipuler ces adresses, il n'y a que deux symboles à retenir :
L'opérateur &¶
ET commercial : "Où est-ce ?" : il permet de récupérer l'adresse d'une variable.
int a = 10;&a-> Donne l'adresse dea(par exemple 0x7ffee4).
L'opérateur *¶
L'étoile : "Va chercher !" : il permet d'accéder à la valeur située à une adresse (Déréférencement).
- Si
pcontient l'adresse dea... *p-> Va à l'adresse indiquée parpet lis (ou modifie) la valeur.- Donc
*pest équivalent àa.
Schéma récapitulatif¶
2. Exercices Pratiques¶
Exercice 1 : Prise en main¶
Écrivez un programme main qui :
- Déclare un entier
n = 5. - Déclare un pointeur
pqui pointe versn. - Affiche la valeur de
ndirectement. - Affiche la valeur de
nen passant par le pointeur (utilisez*). - Modifiez la valeur de
nen utilisant uniquementp(ex:*p = ...). - Affichez
npour vérifier qu'elle a bien changé.
Exercice 2 : Le Swap (Classique absolu)¶
Le but est de créer une fonction qui échange le contenu de deux variables. Le code suivant ne marche pas (pour les raisons vues en Partie 1).
void swap_rate(int a, int b) {
int temp = a;
a = b;
b = temp;
}
// Dans le main, a et b ne seront pas inversés.
Votre mission :
Écrivez la fonction void swap_reussi(int *a, int *b) qui accepte des adresses en paramètres.
- Appelez-la depuis le
mainen lui donnant les adresses de deux variablesxety. - Indice : Pour l'appel, utilisez
swap_reussi(&x, &y). - Indice : Dans la fonction, n'oubliez pas les étoiles
*pour toucher aux vraies valeurs !
Exercice 3 : Division euclidienne (Retourner plusieurs valeurs)¶
Une fonction en C ne peut retourner qu'une seule valeur avec return. Mais grâce aux pointeurs, on peut "remplir" plusieurs variables distantes.
Écrivez une fonction :
void division(int a, int b, int *quotient, int *reste)
Cette fonction doit :
- Calculer la division de
aparb. - Stocker le quotient dans la variable pointée par
quotient. - Stocker le reste dans la variable pointée par
reste.
Tip
en C, l'opérateur / est ambigüe... Appliqué à des entiers, il donne le
quotient de la division entière (5/2 donne 2). Appliqué à des réel, il
donne une valeur approchée du résultat. Mais alors comment trouve t on le reste
? on peut le retrouver à partir du quotient et des opérande, bien sur, mais on
peut aussi l'obtenir directement, c'est le boulot de l'opérateur % : 5%2
donne 1 (5=2x2+1)
Testez-la dans le main :
int q, r;
division(10, 3, &q, &r);
printf("10 / 3 = %d reste %d\n", q, r); // Doit afficher 3 reste 1
Exercice 4 : Pointeurs et Tableaux¶
Un tableau, c'est secrètement un pointeur constant vers la première case.
- Créez un tableau
int tab[] = {10, 20, 30, 40};. - Créez un pointeur
int *p = tab;(Notez qu'il n'y a pas besoin de&ici, cartabest déjà une adresse !). - Affichez
*p. (Cela devrait afficher 10). - Affichez
*(p+1). (Cela devrait afficher 20). - Utilisez une boucle pour parcourir tout le tableau en n'utilisant que le pointeur et l'arithmétique
*(p+i). Interdiction d'utiliser les crochets[]!
Sujet rédigé à l'aide de ChatGPT et Gemini