Chargement...

Lien entre tableaux et pointeurs

Disposition contiguë, conversion en pointeur et arithmétique des pointeurs en C++.

En C++, les tableaux (arrays) et les pointeurs (pointers) sont étroitement liés. Cela s’explique par le fait que les tableaux sont stockés de manière séquentielle en mémoire, et que le nom d’un tableau représente en réalité l’adresse de son premier élément. Il est donc possible de parcourir un tableau à l’aide de l’arithmétique des pointeurs. Dans cet article, nous allons découvrir la structure mémoire des tableaux, leur relation avec les pointeurs et plusieurs exemples pratiques d’utilisation.


1. Disposition en mémoire des tableaux

Lorsqu’un tableau est défini en C++, tous ses éléments sont stockés côte à côte en mémoire. Exemple :


#include <iostream>
using namespace std;

int main() {
    int nombres[3] = {10, 20, 30};

    cout << "Adresse du 1er élément : " << &nombres[0] << endl;
    cout << "Adresse du 2e élément : " << &nombres[1] << endl;
    cout << "Adresse du 3e élément : " << &nombres[2] << endl;

    return 0;
}

Les adresses affichées seront consécutives :


Adresse du 1er élément : 0x61ff0c  
Adresse du 2e élément : 0x61ff10  
Adresse du 3e élément : 0x61ff14

Comme chaque int occupe 4 octets, les adresses augmentent de 4 en 4.


2. Le nom d’un tableau est un pointeur

Le nom du tableau (nombres) représente en réalité l’adresse de son premier élément. Ainsi, nombres et &nombres[0] renvoient à la même adresse.


int nombres[3] = {10, 20, 30};
cout << nombres << endl;      // adresse du premier élément
cout << &nombres[0] << endl; // même adresse

Par conséquent, on peut parcourir un tableau en utilisant un pointeur.


3. Accès aux éléments d’un tableau avec des pointeurs

Si un pointeur pointe vers le premier élément d’un tableau, on peut accéder aux autres éléments grâce à l’arithmétique des pointeurs.


#include <iostream>
using namespace std;

int main() {
    int nombres[4] = {5, 10, 15, 20};
    int *p = nombres; // p = &nombres[0]

    cout << *p << endl;      // 5
    cout << *(p + 1) << endl; // 10
    cout << *(p + 2) << endl; // 15
    cout << *(p + 3) << endl; // 20
}

L’expression *(p + i) est équivalente à nombres[i]. C’est le principe de base de l’arithmétique des pointeurs.


4. Arithmétique des pointeurs

Les pointeurs se déplacent automatiquement dans la mémoire en fonction de leur type. Exemple :


int tableau[3] = {1, 2, 3};
int *ptr = tableau;

cout << ptr << endl;       // adresse du premier élément
ptr++;
cout << ptr << endl;       // adresse de l’élément suivant

L’expression ptr++ déplace l’adresse de 4 octets (int = 4 octets). Ce calcul est effectué automatiquement selon le type du pointeur. Pour un double, le déplacement est de 8 octets, et pour un char, il est de 1 octet.


5. Parcourir un tableau avec un pointeur

On peut parcourir les éléments d’un tableau à l’aide d’un pointeur dans une boucle.


int nombres[] = {2, 4, 6, 8, 10};
int *p = nombres;

for (int i = 0; i < 5; i++) {
    cout << *(p + i) << " ";
}

Une autre méthode consiste à incrémenter directement le pointeur :


for (int *ptr = nombres; ptr < nombres + 5; ptr++) {
    cout << *ptr << " ";
}

Les deux méthodes produisent le même résultat :


2 4 6 8 10

6. Fonctions avec des paramètres de tableau

Lorsqu’un tableau est passé à une fonction, c’est en réalité l’adresse du tableau qui est transmise. La fonction peut donc modifier directement le contenu du tableau.


#include <iostream>
using namespace std;

void Remplir(int *tableau, int longueur) {
    for (int i = 0; i < longueur; i++)
        tableau[i] = (i + 1) * 5;
}

void Afficher(const int *tableau, int longueur) {
    for (int i = 0; i < longueur; i++)
        cout << tableau[i] << " ";
}

int main() {
    int nombres[5];
    Remplir(nombres, 5);
    Afficher(nombres, 5);
}

Comme la fonction Remplir modifie directement le tableau en mémoire, les valeurs dans la fonction main() sont mises à jour.


7. Tableaux multidimensionnels et pointeurs

Les tableaux multidimensionnels sont également stockés de manière séquentielle en mémoire. Cependant, l’arithmétique des pointeurs doit être appliquée avec plus d’attention.


#include <iostream>
using namespace std;

int main() {
    int matrice[2][3] = {
        {1, 2, 3},
        {4, 5, 6}
    };

    cout << *(*(matrice + 0) + 2) << endl; // 3
    cout << *(*(matrice + 1) + 0) << endl; // 4
}

Ici, matrice → représente l’adresse de la première ligne. *(matrice + 1) → se déplace vers la deuxième ligne, et *(*(matrice + 1) + 0) → accède au premier élément de cette ligne.


8. Pointeurs et tableaux dynamiques

Contrairement aux tableaux à taille fixe, les tableaux dynamiques sont créés à l’aide du mot-clé new. Ces tableaux sont stockés dans la mémoire heap et leur taille peut être déterminée pendant l’exécution.


int *tableau = new int[5];

for (int i = 0; i < 5; i++)
    tableau[i] = (i + 1) * 10;

for (int i = 0; i < 5; i++)
    cout << tableau[i] << " ";

delete[] tableau; // Libérer la mémoire

Les tableaux dynamiques nécessitent une gestion manuelle de la mémoire. La mémoire allouée avec new doit toujours être libérée avec delete[] une fois utilisée.


9. Lecture d’un tableau avec un pointeur const

Si vous ne souhaitez pas qu’une fonction modifie le tableau, le paramètre pointeur peut être défini comme const.


void Afficher(const int *tableau, int longueur) {
    for (int i = 0; i < longueur; i++)
        cout << tableau[i] << " ";
}

Cette approche préserve l’intégrité des données et empêche toute modification accidentelle du tableau.


10. TL;DR

  • Le nom du tableau (nombres) → représente l’adresse du premier élément (&nombres[0]).
  • *(p + i)tableau[i] sont équivalents.
  • L’arithmétique des pointeurs avance automatiquement l’adresse selon la taille du type de données.
  • Les tableaux sont passés aux fonctions par adresse, sans copie.
  • Les tableaux multidimensionnels peuvent être parcourus à l’aide de chaînes de pointeurs (*(*(matrice + i) + j)).
  • Les tableaux dynamiques doivent être créés avec new et libérés avec delete[].
  • Tous les exemples peuvent être exécutés avec Visual Studio 2022 ou le compilateur GCC 11+.

Articles connexes