Le quartierC++ C++Pièce 4/7Intermédiaire

Références et pointeurs

Comprendre les adresses mémoire, passer des arguments sans copie avec les références et manipuler des pointeurs en sécurité.

Ce que tu vas apprendre

  • Choisir entre passage par valeur, par référence et par référence constante.
  • Lire et écrire un pointeur : adresse, déréférencement, nullptr.
  • Savoir quand préférer une référence à un pointeur.

Le problème de la copie

Par défaut, une fonction reçoit une copie de ses arguments. Modifier la copie ne change pas l'original :

void doubler(int n) {
    n = n * 2;
}

int main() {
    int portions{4};
    doubler(portions);
    std::cout << portions << "\n";   // affiche 4
}

Pour un int, la copie ne coûte rien. Pour un vecteur de milliers d'éléments, elle coûte cher.

Les références

Une référence est un second nom pour une variable existante. Elle se déclare avec & après le type :

void doubler(int& n) {
    n = n * 2;
}

int main() {
    int portions{4};
    doubler(portions);
    std::cout << portions << "\n";   // affiche 8
}

Ici n désigne directement portions. Aucune copie n'est faite, et la fonction peut modifier l'original.

Une référence doit être initialisée dès sa création et ne peut jamais être réaffectée à une autre variable.

La référence constante

Pour éviter la copie sans autoriser la modification, ajoute const :

void afficher(const std::vector<std::string>& ingredients) {
    for (const auto& i : ingredients) {
        std::cout << i << "\n";
    }
}

C'est la forme la plus courante pour passer des chaînes et des conteneurs en lecture seule.

ParamètreCopie ?Modifie l'original ?
int nOuiNon
int& nNonOui
const int& nNonNon

Règle pratique : petits types (int, double, char, bool) par valeur, gros objets par référence constante, et par référence simple seulement pour modifier.

Adresses et pointeurs

Chaque variable vit à une adresse en mémoire. Un pointeur est une variable qui stocke une adresse. Le * dans la déclaration indique un pointeur, l'opérateur & récupère l'adresse :

int duree{45};
int* p = &duree;

std::cout << p << "\n";    // une adresse, par exemple 0x7ffd...
std::cout << *p << "\n";   // 45
*p = 50;                   // duree vaut maintenant 50

Utiliser *p s'appelle le déréférencement : on accède à la valeur située à l'adresse. Attention, le symbole * a donc deux sens selon l'endroit où il apparaît.

nullptr

Un pointeur peut ne pointer sur rien. On le déclare alors avec nullptr :

int* p = nullptr;

if (p != nullptr) {
    std::cout << *p << "\n";
}
Déréférencer un pointeur nul ou non initialisé est un comportement indéfini : le programme peut planter ou, pire, continuer avec des données fausses. Initialise toujours tes pointeurs, et vérifie-les avant usage.

Pointeur ou référence ?

Les deux désignent un objet sans le copier. Leurs différences :

RéférencePointeur
Peut être « vide »NonOui (nullptr)
Peut changer de cibleNonOui
Syntaxe d'accèsComme une variable*p ou p->

Choisis la référence par défaut. Prends un pointeur seulement quand l'absence de valeur est possible ou que la cible doit changer.

Pointeur vers un objet

Pour accéder à un membre d'un objet via un pointeur, on utilise la flèche ->, raccourci de (*p).. Exemple avec une chaîne :

std::string titre{"Quiche lorraine"};
std::string* p = &titre;

std::cout << p->size() << "\n";   // 15
Les pointeurs « bruts » comme int* ne gèrent pas la mémoire eux-mêmes. Pour posséder un objet alloué dynamiquement, on utilise des pointeurs intelligents, vus au cours 06.

Pièges classiques

  • Retourner une référence vers une variable locale : elle est détruite à la fin de la fonction, la référence devient invalide.
  • Garder un pointeur vers un élément d'un std::vector puis ajouter des éléments : le vecteur peut déplacer ses données en mémoire.
  • Oublier que int* a, b; déclare un pointeur a et un entier b.

À retenir

  • Par défaut, un argument est copié ; une référence T& évite la copie et permet la modification.
  • const T& passe un gros objet en lecture seule, sans copie.
  • Un pointeur contient une adresse : &x la donne, *p lit la valeur pointée.
  • Initialise un pointeur à nullptr et teste-le avant de le déréférencer.
  • Une référence ne peut pas être nulle ni changer de cible, c'est le choix par défaut.
  • p->membre accède à un membre d'un objet pointé.

Pour aller plus loin

Sources officielles

Ensuite

Projet
Lignes de code
Niveau
Le quartier
Appartement
C++
Pièce
4/7
Plan n°
cpp/04.references-et-pointeurs
Lignes de code · fiches rédigées à partir des documentations officielles, sources citées en bas de chaque page.