Skip to content

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 ?

  1. Variable simple (int x) : Le photocopieur. Quand vous passez ma_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_variable dans le main) reste intacte. C'est le "Passage par valeur".

  2. 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 de a (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 p contient l'adresse de a...
  • *p -> Va à l'adresse indiquée par p et lis (ou modifie) la valeur.
  • Donc *p est équivalent à a.

Schéma récapitulatif

\[ \text{Variable } a \xrightarrow{\text{&a (Je demande l'adresse)}} \text{Adresse de } a \]
\[ \text{Pointeur } p \xrightarrow{\text{*p (Je vais voir ce qu'il y a là-bas)}} \text{Valeur de } a \]

2. Exercices Pratiques

Exercice 1 : Prise en main

Écrivez un programme main qui :

  1. Déclare un entier n = 5.
  2. Déclare un pointeur p qui pointe vers n.
  3. Affiche la valeur de n directement.
  4. Affiche la valeur de n en passant par le pointeur (utilisez *).
  5. Modifiez la valeur de n en utilisant uniquement p (ex: *p = ...).
  6. Affichez n pour 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 main en lui donnant les adresses de deux variables x et y.
  • 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 :

  1. Calculer la division de a par b.
  2. Stocker le quotient dans la variable pointée par quotient.
  3. 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.

  1. Créez un tableau int tab[] = {10, 20, 30, 40};.
  2. Créez un pointeur int *p = tab; (Notez qu'il n'y a pas besoin de & ici, car tab est déjà une adresse !).
  3. Affichez *p. (Cela devrait afficher 10).
  4. Affichez *(p+1). (Cela devrait afficher 20).
  5. 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