Hoja de repaso: Gestion des tableaux en programmation C++

📋 Plan du Cours

  1. Types structurés mémoire
  2. Tableaux mémoire
  3. Tableaux multidimensionnels
  4. Tableaux encapsulés
  5. Taille non précisée
  6. Pointeurs tableaux
  7. Conversion tableaux-pointeurs
  8. Paramètres tableaux fonctions
  9. Retour tableaux fonctions
  10. Allocation dynamique
  11. Libération mémoire
  12. Tableaux dynamiques

📖 1. Types structurés mémoire

🔑 Notions clés & Définitions

  • Enregistrement : Collection de champs totalement définis à la déclaration, dont l’occupation mémoire est la somme de celle de ses champs, et dont l’adresse correspond à celle du premier champ (voir section 1).
  • Adresse d’un enregistrement : Adresse du premier champ de l’enregistrement, permettant d’accéder à l’ensemble des champs via cette adresse (voir section 1).
  • Tableau : Séquence de taille fixe composée de cases de type identique, dont l’occupation mémoire est calculée par la formule taille × taille d’une case, et dont l’adresse correspond à celle de la première case (voir section 1).
  • Occupation mémoire d’un enregistrement : Somme des occupations mémoire de tous ses champs, permettant d’évaluer la taille totale en mémoire (voir section 1).
  • Occupation mémoire d’un tableau : Produit de la taille du tableau par la taille d’une case, représentant la mémoire totale occupée par le tableau (voir section 1).
  • Adresse d’un tableau : Adresse de la première case du tableau, utilisée comme référence pour accéder aux autres cases par décalage (voir section 1).

📝 Points essentiels

  • La mémoire d’un enregistrement est calculée en additionnant la mémoire occupée par chacun de ses champs, ce qui facilite la gestion de la mémoire lors de l’allocation et de l’accès (voir section 1).
  • La adresse d’un enregistrement ou d’un tableau est celle du premier champ ou de la première case, ce qui permet d’accéder à l’ensemble des données via cette référence.
  • La taille fixe des tableaux garantit une occupation mémoire déterminée par la formule taille × taille d’une case, simplifiant la gestion mémoire lors de la déclaration et de l’accès.
  • La distinction entre adresse d’un enregistrement et adresse d’un tableau est essentielle pour la manipulation mémoire, notamment lors de l’utilisation de pointeurs ou d’allocations dynamiques (voir section 1).
  • La compréhension de ces concepts permet d’optimiser la gestion mémoire dans la programmation algorithmique et en C++, en évitant les erreurs d’adressage ou de surcharge mémoire.

💡 À retenir

Les enregistrements et tableaux sont des types structurés dont la gestion mémoire repose sur la somme ou le produit de la taille des champs ou cases, avec une adresse de référence correspondant au premier champ ou à la première case, facilitant leur manipulation et leur allocation.

📖 2. Tableaux mémoire

🔑 Notions clés & Définitions

  • Tableau : séquence contiguë de cases mémoire de même type, dont la taille est définie lors de la déclaration. Selon XLG2IE011 (2025-2026), il s'agit d'une structure où chaque case est accessible par un indice, et les adresses des cases sont consécutives en mémoire.

  • Adresse d'un élément tableau : calculée par la formule adresse de base + indice, où l'adresse de base correspond à celle de la première case mémoire du tableau. La formule permet un accès direct à chaque élément par son indice.

  • Occupation mémoire d’un tableau : correspond à la capacité totale en éléments multipliée par la taille d’un élément, soit nombre d’éléments × taille élément. Elle représente l’espace mémoire occupé par le tableau en mémoire contiguë.

  • Séquence contiguë : propriété essentielle d’un tableau où toutes ses cases mémoire sont alignées de façon continue, facilitant l’accès par indice et la manipulation efficace en algorithmique.

  • Exemple d’accès et modification par indice : si fou est un tableau de 99 Personnes, alors fou[1] désigne la première case (indice 1), accessible directement, et on peut modifier ses champs comme fou[1].nom ou fou[1].age.

📝 Points essentiels

  • La mémoire d’un tableau est organisée en une séquence contiguë, ce qui permet un accès rapide par indice grâce à la formule d’adresse : adresse_element = adresse_base + indice (voir XLG2IE011, 2025-2026).

  • La taille mémoire d’un tableau est calculée par nombre d’éléments × taille d’un élément, ce qui facilite la gestion de l’occupation mémoire et l’allocation.

  • La propriété de séquence contiguë permet d’accéder efficacement à chaque élément par son indice, en utilisant l’arithmétique de pointeurs : adresse + indice × taille élément.

  • La gestion de l’adresse d’un tableau est simplifiée par sa nature contiguë, mais il faut faire attention à ne pas dépasser la capacité allouée pour éviter des erreurs d’accès.

  • Lors de l’accès à un élément par indice, la formule d’adresse permet de modifier directement la valeur stockée dans la case mémoire correspondante.

💡 À retenir

Un tableau est une séquence contiguë de cases mémoire de même type, dont l’adresse d’un élément est calculée par la formule adresse de base + indice, et dont l’occupation mémoire est proportionnelle à sa taille et à son nombre d’éléments. La propriété de contiguïté facilite un accès rapide et direct à chaque élément par indice.

📖 3. Tableaux multidimensionnels

🔑 Notions clés & Définitions

  • Tableau de tableaux : structure composée de plusieurs tableaux, chaque tableau étant une dimension supplémentaire, permettant la représentation multidimensionnelle.
  • Occupation mémoire totale : calculée comme le produit des dimensions par la taille de l’élément, représentant la mémoire nécessaire pour stocker un tableau multidimensionnel.
  • Adresse d’un élément multidimensionnel : calculée à partir des indices de chaque dimension, en utilisant une formule qui combine ces indices pour accéder à la position mémoire exacte.
  • Exemple de tableau 2D : un tableau de N1 tableaux, chacun contenant N2 éléments, considéré comme un tableau de tableaux.
  • Tableau 2D : tableau de N1 tableaux de N2 éléments, où chaque sous-tableau est accessible par un indice, et l’adresse d’un élément est déterminée par la formule d’indexation.

📝 Points essentiels

  • La mémoire occupée par un tableau multidimensionnel est le produit de toutes ses dimensions multiplié par la taille de l’élément, ce qui permet d’estimer l’espace nécessaire.
  • La représentation en mémoire d’un tableau 2D est un tableau de tableaux, chaque sous-tableau étant une ligne ou une colonne selon l’orientation choisie.
  • La localisation d’un élément dans un tableau multidimensionnel se calcule en combinant les indices de chaque dimension, en utilisant la formule d’adressage : adresse = adresse de base + somme des indices pondérés par leurs tailles respectives.
  • Un tableau 2D peut être vu comme un tableau de N1 tableaux, chacun de N2 éléments, permettant une gestion flexible et modulaire des données.
  • La gestion de l’adresse d’un élément dans un tableau multidimensionnel repose sur la formule d’indexation, qui permet de passer d’un accès logique à une adresse mémoire physique.

💡 À retenir

Les tableaux multidimensionnels sont des structures composées de tableaux de tableaux, dont l’adresse d’un élément se calcule à partir des indices en utilisant une formule d’adressage spécifique, et leur occupation mémoire est proportionnelle au produit de leurs dimensions.

📖 4. Tableaux encapsulés

🔑 Notions clés & Définitions

  • Tableau encapsulé : Enregistrement contenant un tableau, sa capacité et son occupation, permettant une gestion dynamique.
    Christophe Jermann (2025-2026) : structure qui stocke un tableau avec ses paramètres pour une gestion efficace de tableaux partiellement remplis.

  • Capacité : Nombre total d’éléments que peut contenir le tableau encapsulé, stocké dans le champ capacité.
    Christophe Jermann (2025-2026) : limite maximale du tableau, définie lors de l’allocation ou de la réallocation.

  • Occupation : Nombre d’éléments actuellement utilisés dans le tableau encapsulé, stocké dans le champ occupation.
    Christophe Jermann (2025-2026) : indicateur du nombre d’éléments remplis, utilisé pour la gestion dynamique.

  • Stockage de la capacité et occupation pour gestion dynamique : technique consistant à suivre en permanence ces deux paramètres pour ajuster la taille du tableau selon l’utilisation réelle.
    Christophe Jermann (2025-2026) : principe fondamental pour la gestion efficace de tableaux partiellement remplis.

📝 Points essentiels

  • Le tableau encapsulé est une structure d’enregistrement comprenant au minimum trois champs : data (le tableau), capacité (taille maximale) et occupation (nombre d’éléments utilisés).
  • La gestion dynamique repose sur la mise à jour de ces deux paramètres (capacité et occupation) pour éviter la surcharge ou le gaspillage mémoire.
  • La structure permet de manipuler efficacement des tableaux partiellement remplis en évitant la réallocation constante ou le dépassement de capacité.
  • La capacité est généralement fixée lors de l’allocation initiale ou lors d’une réallocation, tandis que l’occupation évolue au fil des insertions ou suppressions.
  • Exemple de structure :
    type TabEncapsulé = Enregistrement
        data : Tableau de Réels
        capacité : Entier
        occupation : Entier
    Fin Enregistrement
    
  • La gestion de la capacité et de l’occupation permet d’implémenter des opérations telles que l’ajout, la suppression ou la réallocation de manière efficace.

💡 À retenir

Le tableau encapsulé combine stockage et gestion dynamique, en utilisant les champs capacité et occupation pour optimiser l’utilisation mémoire lors de manipulations partielles.

📖 5. Taille non précisée

🔑 Notions clés & Définitions

  • Tableau de taille non précisée : tableau dont la taille n’est pas indiquée lors de la déclaration, mais qui peut être utilisé via des pointeurs ou paramètres de fonction (voir section 8). La taille est alors déterminée dynamiquement ou lors de l’allocation, sans être explicitement connue dans la déclaration.

  • Paramètres de fonction : paramètres déclarés sans taille précise, par exemple void f(double tab[]), permettant l’utilisation de tableaux de taille variable ou inconnue. La taille est généralement omise car elle est déjà connue dans l’appelant (voir section 8).

  • Pointeurs : variables stockant l’adresse d’un tableau ou d’un élément, permettant de manipuler des tableaux de taille indéfinie ou dynamique. Lorsqu’un tableau est converti en pointeur (dégradation), la taille n’est pas accessible via sizeof (voir section 7).

  • Généricité des sous-algorithmes : capacité à écrire des algorithmes ou fonctions qui manipulent des tableaux de tailles différentes sans spécifier explicitement la taille, grâce à l’utilisation de paramètres de type tableau non précisés ou de pointeurs (voir section 8).

  • sizeof : opérateur qui retourne la taille en octets d’un tableau en mémoire, ne fonctionne pas pour un tableau passé en paramètre sous forme de pointeur ou de tableau de taille non précisée, car l’information de taille est perdue lors de la dégradation (voir section 1 et 7).

📝 Points essentiels

  • La déclaration d’un tableau sans taille précise est interdite sauf pour certains cas : paramètres de fonction et pointeurs. En effet, pour un paramètre TYPE tab[], la taille est omise car elle est implicite dans l’appel, permettant ainsi la généricité des sous-algorithmes (voir section 8).

  • La taille d’un tableau non précisée ne peut pas être déterminée par sizeof car, lors de la dégradation en pointeur, l’information sur la taille est perdue. La seule façon de connaître la taille est de la gérer explicitement via des variables ou des paramètres (voir section 7).

  • En C++, la syntaxe void f(double tab[]) est équivalente à void f(double* tab), ce qui montre que la taille n’est pas conservée dans la déclaration. La gestion de la taille doit donc être assurée par des variables ou des conventions dans le code.

  • La généricité permet d’écrire des sous-algorithmes qui manipulent des tableaux de tailles différentes, en utilisant des paramètres de type tableau non précisés ou des pointeurs, et en utilisant une opération pour obtenir la taille lors de l’utilisation (voir section 8).

  • La gestion dynamique de la taille via allocation et réallocation permet d’adapter la capacité du tableau à l’utilisation réelle, évitant ainsi le gaspillage mémoire ou la perte de données (voir section 4 et 28).

💡 À retenir

Les tableaux de taille non précisée offrent une flexibilité essentielle en algorithmique et en programmation, mais nécessitent une gestion explicite de la taille, notamment lors de l’allocation, de la manipulation et de la libération mémoire, en raison de la perte d’information lors de la conversion en pointeur.

📖 6. Pointeurs tableaux

🔑 Notions clés & Définitions

  • Adresse du premier élément : L'adresse mémoire du début d'un tableau, accessible via un pointeur vers tableau ou par dégradation automatique (array-to-pointer decay) en C++. Selon PERROUX (date), cette adresse permet d’accéder à l’ensemble des éléments du tableau en utilisant l’arithmétique des pointeurs.

  • Déréférencement d’un pointeur vers tableau : Opération consistant à accéder au tableau pointé par un pointeur en utilisant l’opérateur *. Cela donne accès à l’ensemble du tableau, permettant d’utiliser des opérations comme la taille ou l’accès par indice. En C++, *p désigne le tableau pointé, et *p[i] l’élément d’indice i.

  • Opérations possibles :

    • Taille : La taille d’un tableau pointé peut être obtenue via une opération spécifique (ex. taille(tab) ou |tab|), mais la taille n’est pas directement accessible via le pointeur seul.
    • Accès par indice : Utilisation de la notation mémoire(p)[i] ou *(p + i) pour accéder à l’élément d’indice i.
    • Passage en paramètre : Un tableau peut être passé à une fonction via un pointeur, permettant d’accéder et de modifier ses éléments. La différence entre affectation d’adresse (p = &tab[0]) et affectation de tableau (p = tab) est essentielle : la première affecte l’adresse du premier élément, la seconde réalise une dégradation automatique du tableau en pointeur.
  • Différence entre affectation d’adresse et affectation de tableau :

    • Affectation d’adresse (p = &tab[0]) : affecte à p l’adresse du premier élément du tableau.
    • Affectation de tableau (p = tab) : en C++, cette opération est une dégradation automatique du tableau en pointeur vers son premier élément, mais ne copie pas le tableau. La distinction est importante pour la gestion mémoire et la sécurité.
    • Note : La dégradation (array-to-pointer decay) entraîne la perte d’information sur la taille du tableau, ce qui doit être précisé par d’autres moyens (ex. |tab|).

📝 Points essentiels

  • Un pointeur vers tableau est souvent déclaré comme type *pTab, où pTab pointe vers la première case du tableau. La dégradation automatique en C++ permet d’utiliser un tableau comme un pointeur vers son premier élément, mais la taille du tableau n’est pas conservée dans le pointeur seul, ce qui limite certaines opérations.

  • La différence entre affectation d’adresse (p = &tab[0]) et affectation de tableau (p = tab) est cruciale : la première concerne une affectation explicite d’adresse, la seconde une dégradation automatique du tableau en pointeur.

  • La gestion des opérations sur un pointeur vers tableau inclut la taille du tableau, accessible via une opération spécifique, et l’accès aux éléments par indice ou arithmétique de pointeurs. La taille du tableau n’étant pas stockée dans le pointeur, il faut la gérer séparément (ex. |tab|).

  • La conversion automatique d’un tableau en pointeur (array-to-pointer decay) permet d’utiliser le tableau comme un pointeur, mais entraîne la perte d’informations sur la taille, ce qui doit être explicitement géré pour éviter les erreurs.

💡 À retenir

Un pointeur vers tableau en C++ désigne l’adresse du premier élément, mais la distinction entre affectation d’adresse et dégradation automatique est essentielle pour une gestion correcte de la mémoire et des opérations sur les tableaux. La taille du tableau doit être conservée séparément, car elle n’est pas implicite dans le pointeur.

📖 7. Conversion tableaux-pointeurs

🔑 Notions clés & Définitions

  • Dégradation de tableau en pointeur (array-to-pointer decay) : en C++, lorsqu’un tableau est utilisé dans une expression, il est automatiquement converti en pointeur vers son premier élément, ce qui entraîne la perte d’information sur la taille du tableau. (source : Christophe Jermann, 2025-2026)

  • *Égalités tab == &tab[0] et tab == tab[0] : en raison de la dégradation, un tableau tab est équivalent à l’adresse de sa première case (&tab[0]), et le déréférencement *tab donne la valeur du premier élément. (source : Christophe Jermann, 2025-2026)

  • Pointeur vers type élément, pas vers tableau : en C++, un pointeur déclaré comme int* p pointe vers un seul élément de type int, et non vers un tableau complet. La conversion automatique ne permet pas de déclarer un pointeur spécifique à un tableau, mais uniquement vers le type des éléments. (source : Christophe Jermann, 2025-2026)

📝 Points essentiels

  • Lorsqu’un tableau est utilisé dans une expression, il est converti en pointeur vers son premier élément, ce qui simplifie l’accès mais entraîne la perte d’information sur la taille du tableau (d’où le terme "decay"). Cette conversion est automatique en C++ : "array-to-pointer decay".

  • La conversion implique que tab (tableau) et &tab[0] (adresse de la première case) sont équivalents, et que *tab (déréférencement) correspond à la valeur du premier élément. Cependant, il ne faut pas confondre un pointeur vers un seul élément et un pointeur vers un tableau, car le pointeur ne contient pas d’information sur la taille du tableau.

  • La déclaration d’un pointeur vers un tableau de taille fixe doit se faire explicitement, par exemple int (*p)[N], pour éviter toute ambiguïté. La conversion automatique ne s’applique qu’aux tableaux de taille non précisée ou dans le contexte d’une dégradation implicite.

  • La vigilance est essentielle lors de l’utilisation de tableaux et pointeurs en C++, car cette dégradation peut conduire à des erreurs subtiles, notamment lors de passages en paramètre ou d’affectations, d’où l’importance de commentaires explicatifs pour clarifier le rôle de chaque variable.

💡 À retenir

En C++, un tableau se convertit automatiquement en pointeur vers son premier élément, mais cette opération entraîne la perte d’information sur sa taille. La compréhension de cette dégradation est cruciale pour éviter les erreurs lors de la manipulation de tableaux et pointeurs.

📖 8. Paramètres tableaux fonctions

🔑 Notions clés & Définitions

  • Passage par référence à tableau de taille fixe : syntaxe permettant de transmettre un tableau d’une taille précise à une fonction sans decay, en utilisant la référence à un tableau de taille N, par exemple : void f(const int (&t)[3]). Cela évite la perte d’information sur la taille du tableau lors de l’appel.

  • Decay (dégrader un tableau en pointeur) : conversion automatique en C++ où un tableau passé en paramètre est traité comme un pointeur vers son premier élément, par exemple : void g(int p[]). Cela entraîne la perte d’informations sur la taille du tableau.

  • Passage de tableau en paramètre avec const et référence : syntaxe recommandée pour passer un tableau en lecture seule tout en conservant sa taille, par exemple : void f(const int (&t)[N]). Elle évite le decay et garantit la taille lors de l’appel.

  • Exemple de syntaxe correcte pour éviter decay : void f(const int (&t)[N]) pour un tableau de taille N en entrée, permettant d’accéder à la taille via N et d’éviter la conversion implicite en pointeur.

  • Différence entre passage par référence et passage par pointeur : le passage par référence à un tableau de taille fixe conserve la taille du tableau et empêche le decay, tandis que le passage par pointeur (int p[]) ou int* p ne conserve pas cette information, ce qui peut compliquer la gestion de la taille dans la fonction.

📝 Points essentiels

  • La syntaxe void f(const int (&t)[N]) permet de passer un tableau de taille N par référence, évitant ainsi le decay, et garantit que la taille est connue dans la fonction. Elle est particulièrement utile pour des tableaux de taille fixe, notamment dans les algorithmes où la taille doit être conservée.

  • Le passage par pointeur (int p[] ou int* p) entraîne un decay automatique du tableau, ce qui signifie que la fonction ne connaît plus la taille du tableau passé, sauf si celle-ci est transmise séparément ou si la taille est déterminée par d’autres moyens.

  • La différence fondamentale réside dans la conservation ou non de la taille du tableau lors de la transmission à une fonction. La référence à tableau fixe (&t[N]) permet de préserver cette information, contrairement au pointeur.

  • La syntaxe const int (&t)[N] est recommandée pour les paramètres en lecture seule, pour éviter la modification accidentelle et pour garantir la taille du tableau dans la fonction.

  • La conversion automatique (decay) d’un tableau en pointeur est une opération implicite qui peut entraîner des erreurs si la taille du tableau n’est pas explicitement gérée.

💡 À retenir

Pour passer un tableau en paramètre sans perdre d’informations sur sa taille, il faut utiliser la syntaxe void f(const int (&t)[N]), qui évite le decay et garantit la connaissance de la taille dans la fonction. Le passage par pointeur (int p[]) ne conserve pas cette information, ce qui peut compliquer la gestion dans les algorithmes.

📖 9. Retour tableaux fonctions

🔑 Notions clés & Définitions

  • Impossible de retourner un tableau directement en C++ : en C++, la syntaxe TYPE[N] pour le retour de fonction n’est pas autorisée, car cela impliquerait de retourner un tableau par valeur, ce qui est interdit. La solution consiste à retourner un pointeur vers le tableau (type TYPE*), ce qui entraîne des risques liés à la gestion de la mémoire et à la durée de vie des variables (voir CRITIQUE).
  • Fonction retournant un pointeur vers tableau : en C++, une fonction peut retourner un pointeur (TYPE*) pointant vers un tableau alloué dynamiquement ou existant en mémoire, mais cela ne garantit pas la sécurité si la mémoire est locale ou désallouée (voir CRITIQUE).
  • Risques liés au retour de pointeur sur variable locale : si une fonction retourne un pointeur vers une variable locale (par exemple, un tableau local), la mémoire sera désallouée à la sortie de la fonction, rendant le pointeur invalide et provoquant des comportements indéfinis (voir CRITIQUE).
  • Convention : utiliser procédures avec tableaux en sortie : pour éviter ces risques, il est recommandé d’utiliser des procédures (ou sous-algorithmes) qui prennent en paramètre un tableau en sortie, souvent avec des préconditions sur la capacité du tableau, afin de gérer explicitement la mémoire et la capacité (voir CRITIQUE).
  • Préconditions sur capacité des tableaux en sortie : lors de l’utilisation de procédures pour retourner des données dans un tableau, il est essentiel de garantir que la capacité du tableau en sortie est suffisante pour contenir toutes les données, afin d’éviter les dépassements ou pertes de données (voir CRITIQUE).

📝 Points essentiels

  • En C++, il est impossible de retourner directement un tableau dans une fonction, car la syntaxe TYPE[N] n’est pas autorisée pour le retour. La pratique recommandée est d’utiliser un pointeur vers tableau (TYPE)* ou une structure encapsulant le tableau, mais cela comporte des risques liés à la gestion mémoire (voir CRITIQUE).
  • La conversion implicite d’un tableau en pointeur (décay) entraîne une perte d’information sur la taille du tableau, rendant difficile la gestion de la capacité et la sécurité lors de l’utilisation du pointeur retourné (voir CRITIQUE).
  • La convention en algorithmique et en C++ est de ne pas faire retourner directement un tableau dans une fonction, mais d’utiliser des procédures avec tableaux en sortie, en imposant des préconditions sur la capacité pour assurer la cohérence (voir CRITIQUE).
  • Lorsqu’on retourne un tableau via un pointeur, il faut faire attention à la durée de vie de la mémoire : si le tableau est local à la fonction, il sera désalloué à la sortie, ce qui rend le pointeur invalide (voir CRITIQUE).
  • La gestion dynamique des tableaux (allocation, réallocation, libération) permet d’adapter la taille du tableau à l’utilisation réelle, mais nécessite une gestion rigoureuse pour éviter les fuites mémoire ou erreurs d’accès (voir CRITIQUE).

💡 À retenir

En C++, il est interdit de retourner un tableau directement dans une fonction ; il faut privilégier l’utilisation de procédures avec tableaux en sortie ou de pointeurs vers tableaux alloués dynamiquement, en respectant strictement la gestion mémoire pour garantir la sécurité et la cohérence du programme.

📖 10. Allocation dynamique

🔑 Notions clés & Définitions

  • Allocation dynamique : Technique permettant de réserver de la mémoire à l'exécution selon le besoin réel, en dimensionnant la structure lors de l'exécution (voir section 3).
  • Utilisation de pointeurs pour stocker l'adresse : Les pointeurs contiennent l'adresse du début du tableau alloué, permettant d'accéder et de manipuler la mémoire allouée (voir section 6).
  • Allocation avec new[] en C++ : Opération d'allocation de mémoire pour un tableau de taille variable en C++, utilisant l'instruction new[] pour réserver dynamiquement un espace mémoire contigu (voir section 12).
  • Nécessité de désallocation : Après utilisation, il est impératif de libérer la mémoire allouée avec delete[] pour éviter les fuites mémoire, en réinitialisant le pointeur à nullptr (voir section 11).
  • Exemple d'allocation : Allocation d’un tableau de taille saisie par l’utilisateur, par exemple pNotes = new double[taille];, puis désallocation avec delete[] pNotes;.

📝 Points essentiels

L’allocation dynamique répond à la problématique de taille inconnue au moment de la programmation, permettant d’ajuster la mémoire à la taille réelle des données (voir section 3). En C++, la mécanique repose sur l’utilisation de new[] pour réserver et delete[] pour libérer la mémoire, en respectant la règle d’association : new[] doit toujours être suivi de delete[]. La gestion de tableaux multidimensionnels se fait par allocation successives de pointeurs vers pointeurs, en libérant chaque sous-tableau avant de libérer le tableau principal (voir section 24). La libération est cruciale pour éviter les fuites mémoire, et il est conseillé de réinitialiser les pointeurs à nullptr après désallocation (voir section 11). La gestion d’un tableau dynamique inclut aussi la réallocation pour ajuster la capacité lors de l’ajout ou retrait de données, en recopiant les données dans un nouveau tableau plus adapté, puis en libérant l’ancien (voir section 29). La bibliothèque standard C++ propose également le type vector<T> pour gérer automatiquement ces opérations, avec des stratégies de redimensionnement intégrées (voir section 34).

💡 À retenir

L’allocation dynamique permet de dimensionner précisément la mémoire nécessaire à l’exécution, mais exige une gestion rigoureuse pour libérer la mémoire et éviter les fuites, notamment via new[] et delete[] en C++.

📖 11. Libération mémoire

🔑 Notions clés & Définitions

  • Libération mémoire avec delete[] : opération en C++ permettant de désallouer la mémoire allouée dynamiquement à un tableau avec new[]. Elle doit obligatoirement être associée à une allocation avec new[] pour éviter les fuites mémoire.
  • Correspondance new[] ↔ delete[] : règle fondamentale en C++ : chaque nouvelle allocation avec new[] doit être suivie d'une désallocation avec delete[] pour assurer la gestion correcte de la mémoire.
  • Réinitialisation des pointeurs inutilisés à nullptr : pratique recommandée pour éviter les pointeurs pendants (dangling pointers), en leur assignant la valeur nullptr après libération, ce qui facilite la détection d’accès à une mémoire désallouée.
  • Libération mémoire pour tableaux multidimensionnels alloués dynamiquement : processus spécifique en C++ pour libérer une matrice 2D ou plus, allouée par pointeurs imbriqués, en libérant d’abord chaque sous-tableau puis le tableau principal. Exemple : libération d’une matrice 2D allouée par pointeurs de pointeurs.
  • Exemple de libération matrice 2D : pour une matrice allouée dynamiquement en C++, il faut faire un delete[] sur chaque sous-tableau, puis sur le tableau principal, pour éviter les fuites mémoire et respecter la correspondance new[] / delete[].

📝 Points essentiels

  • La gestion de la mémoire dynamique en C++ repose sur l’utilisation stricte de new[] pour l’allocation et delete[] pour la désallocation, afin d’éviter les fuites mémoire et les comportements indéfinis.
  • La règle new[] ↔ delete[] est impérative : utiliser delete[] sur un tableau alloué avec new[], et non delete seul, qui est réservé à la désallocation d’un seul objet.
  • Après libération, il est conseillé de réinitialiser le pointeur à nullptr pour éviter des accès accidentels à une mémoire libérée, ce qui pourrait provoquer des erreurs difficiles à diagnostiquer.
  • La libération d’un tableau multidimensionnel alloué dynamiquement doit suivre une procédure précise : libérer chaque sous-tableau avec delete[] puis le tableau principal, pour assurer une gestion correcte de la mémoire.
  • Exemple pratique : pour une matrice 2D allouée par pointeurs imbriqués, il faut d’abord libérer chaque ligne, puis le tableau de pointeurs.

💡 À retenir

La libération correcte de la mémoire dynamique en C++ repose sur l’utilisation stricte de delete[] en correspondance avec new[], accompagnée de la réinitialisation des pointeurs à nullptr pour garantir la sécurité et l’efficacité de la gestion mémoire.

📖 12. Tableaux dynamiques

🔑 Notions clés & Définitions

  • Tableaux encapsulés : structures de stockage contenant un tableau, sa capacité et son occupation, permettant la gestion dynamique de la mémoire (voir section 4).
  • Gestion automatique de capacité et occupation : mécanisme qui ajuste la taille d’un tableau en fonction de son taux de remplissage, pour optimiser mémoire et performance (voir slide 32).
  • Réallocation pour ajuster la taille : opération consistant à allouer un nouveau tableau de taille modifiée, recopier les données de l’ancien, puis libérer l’ancien (voir slides 29-31).
  • Tableaux de taille non précisée : tableaux dont la taille n’est pas fixée à la déclaration, permettant une plus grande flexibilité dans la gestion dynamique (voir slide 8).
  • Pointeurs vers tableaux : adresses de tableaux alloués dynamiquement, permettant leur manipulation via des opérations de déréférencement et de gestion mémoire (voir slides 11-13).

📝 Points essentiels

  • La gestion d’un tableau dynamique repose sur la capacité à ajuster sa taille en fonction de l’occupation, en utilisant la réallocation (allocation, copie, libération).
  • La stratégie de réallocation doit prendre en compte le taux de remplissage (occupation / capacité) et des paramètres comme les facteurs d’agrandissement ou de réduction pour optimiser performance et mémoire.
  • La mécanique d’allocation/désallocation en C++ utilise new[] et delete[], et doit respecter la règle d’équivalence pour éviter fuite mémoire ou erreurs (voir slides 22-25).
  • La gestion d’un tableau dynamique doit être accompagnée de sous-algorithmes spécifiques pour l’allocation et la libération, notamment pour les tableaux multidimensionnels.
  • La bibliothèque standard C++ propose le type vector<T> pour simplifier la gestion automatique des tableaux dynamiques, avec des performances garanties selon la complexité asymptotique.

💡 À retenir

Les tableaux dynamiques permettent de gérer efficacement des structures de données dont la taille varie durant l’exécution, en utilisant la réallocation contrôlée pour optimiser mémoire et performance.

📊 Tableaux de Synthèse

ThèmeDéfinition / CaractéristiquesAuteur / Référence
EnregistrementCollection de champs, adresse du premier champ, occupation mémoire = somme des champs
TableauSéquence fixe de cases de même type, adresse de la première case, occupation mémoire = taille × taille d’une case
Tableau multidimensionnelStructure de tableaux de tableaux, adresse calculée via indices, occupation mémoire = produit des dimensions × taille d’un élément
Tableau encapsuléEnregistrement avec tableau, capacité, occupation, gestion dynamique (Jermann, 2025-2026)Christophe Jermann (2025-2026)
Allocation dynamiqueRéservation mémoire à l’exécution, gestion flexible de la taille
Libération mémoireDésallocation mémoire pour éviter fuite, libérer la mémoire allouée dynamiquement

⚠️ Pièges & Confusions Fréquentes

  1. Confondre l’adresse d’un enregistrement et celle d’un tableau (premier champ vs première case).
  2. Oublier que la taille d’un tableau est fixe lors de la déclaration, ce qui peut causer des dépassements.
  3. Confondre la formule d’adresse d’un tableau unidimensionnel avec celle d’un tableau multidimensionnel.
  4. Négliger la propriété de mémoire contiguë d’un tableau, menant à des erreurs d’accès ou de manipulation.
  5. Mal calculer l’occupation mémoire en ne tenant pas compte de la taille de chaque élément.
  6. Confondre la gestion mémoire statique et dynamique, notamment lors de l’allocation ou libération.
  7. Omettre de vérifier la capacité lors de l’utilisation de tableaux encapsulés ou dynamiques.

✅ Checklist Examen

  1. Connaître la définition d’un enregistrement et son adresse selon la section 1.
  2. Savoir calculer l’occupation mémoire d’un tableau fixe en utilisant la formule taille × nombre d’éléments.
  3. Expliquer la différence entre adresse d’un tableau et adresse d’un enregistrement.
  4. Maîtriser la formule d’adressage d’un tableau unidimensionnel : adresse = adresse de base + indice × taille d’un élément.
  5. Décrire la représentation mémoire d’un tableau multidimensionnel et la formule pour accéder à un élément.
  6. Savoir que la mémoire d’un tableau multidimensionnel est le produit de ses dimensions × taille d’un élément.
  7. Connaître la structure d’un tableau encapsulé selon Christophe Jermann (2025-2026).
  8. Comprendre la gestion dynamique de tableaux avec allocation et libération mémoire.
  9. Savoir différencier allocation statique et dynamique, et leurs implications.
  10. Maîtriser la gestion mémoire pour éviter fuite ou surcharge.
  11. Connaître la formule d’adresse pour un tableau multidimensionnel.
  12. Vérifier la capacité lors de l’utilisation de tableaux encapsulés ou dynamiques.

Pon a prueba tus conocimientos

Pon a prueba tus conocimientos sobre Gestion des tableaux en programmation C++ con 12 preguntas de opción múltiple con correcciones detalladas.

1. Qu'est-ce qu'un type structuré mémoire ?

2. Quel auteur a travaillé sur la notion de tableaux encapsulés durant l'année 2025-2026 ?

Realiza el cuestionario →

Repasa con tarjetas de memoria

Memoriza los conceptos clave de Gestion des tableaux en programmation C++ con 24 tarjetas de memoria interactivas.

Types structurés mémoire — définitions ?

Enregistrement, tableau, multidimensionnel, encapsulé.

Enregistrement — adresse ?

Adresse du premier champ.

Tableau — occupation mémoire ?

Taille × taille d’une case.

Ver tarjetas de memoria →

Similar courses

Crea tus propias hojas de repaso

Importa tu curso y la IA genera hojas, cuestionarios y tarjetas de memoria en 30 segundos.

Generador de hojas