Cours : Programmation avancée en C
Fiche de Cours : Programmation avancée en C (MP2I)
Section titled “Fiche de Cours : Programmation avancée en C (MP2I)”Cette fiche couvre les aspects avancés du langage C au programme de la filière MP2I : gestion dynamique de la mémoire, structures de données fondamentales, manipulation des bits et complexité algorithmique. La rigueur de représentation en machine y est particulièrement exigée.
1. Gestion dynamique de la mémoire et pointeurs avancés
Section titled “1. Gestion dynamique de la mémoire et pointeurs avancés”A. L’alignement et l’opérateur sizeof
Section titled “A. L’alignement et l’opérateur sizeof”La mémoire est adressable par octets. Cependant, l’accès à un type de données de octets (avec souvent puissance de 2) s’effectue plus efficacement si l’adresse est un multiple de (contrainte d’alignement).
- Définition (
sizeof) : L’opérateursizeofrenvoie la taille en octets d’un type ou d’une expression sous la forme d’un entier non signé (size_t). - Piège majeur :
sizeofest évalué à la compilation (sauf pour les VLA - Variable Length Arrays). Il ne faut jamais passer d’expression comportant des effets de bord à l’intérieur desizeof.
B. Allocation dynamique : malloc, calloc, realloc, free
Section titled “B. Allocation dynamique : malloc, calloc, realloc, free”Inclus via <stdlib.h>.
void* malloc(size_t size): Alloue un bloc desizeoctets non initialisés. RenvoieNULLen cas d’échec.void* calloc(size_t nmemb, size_t size): Alloue un bloc pournmembéléments desizeoctets et initialise tous les bits à zéro.void* realloc(void* ptr, size_t size): Redimensionne le bloc pointé parptràsizeoctets. SiptrestNULL, équivaut àmalloc(size). Sisizeest etptrnonNULL, libère le bloc et renvoieNULL(comportement dépendant de l’implémentation, à éviter).
Théorème (Sécurité d’allocation) : Tout appel à
malloc,callocoureallocdoit obligatoirement être suivi d’un test de non-nullité du pointeur retourné avant toute déréférenciation.
int *tab = malloc(n * sizeof(int));if (tab == NULL) { // Gestion de l'erreur fatale (ex: exit(EXIT_FAILURE))}void free(void* ptr): Libère le bloc mémoire pointé parptr. SiptrestNULL,freene fait rien.- Piège (Fuite de mémoire et double free) : Oublier de libérer un bloc alloué provoque une fuite mémoire. Libérer deux fois le même pointeur mène à un comportement indéfini (corruption de la heap). Après un
free(ptr), il est fortement conseillé de poserptr = NULL;.
2. Structures, Unions et Types Opaque
Section titled “2. Structures, Unions et Types Opaque”A. Structures (struct) et Champs de bits
Section titled “A. Structures (struct) et Champs de bits”Une structure permet de regrouper des variables de types potentiellement différents.
- Alignement et Padding : Le compilateur insère des octets de remplissage (padding) pour que chaque champ respecte sa contrainte d’alignement.
- Méthode : Pour optimiser la mémoire, ordonner les champs de la structure par taille décroissante.
// Structure mal optimisée (génère du padding)struct Bad { char c; // 1 octet + 3 octets de padding int i; // 4 octets char d; // 1 octet + 3 octets de padding}; // sizeof(struct Bad) == 12 octets
// Structure optimiséestruct Good { int i; // 4 octets char c; // 1 octet char d; // 1 octet + 2 octets de padding}; // sizeof(struct Good) == 8 octetsB. Unions (union)
Section titled “B. Unions (union)”Une union partage la même zone mémoire pour tous ses membres. La taille d’une union est celle de son plus grand membre (plus l’éventuel padding).
3. Manipulation de bits et Opérateurs bit à bit
Section titled “3. Manipulation de bits et Opérateurs bit à bit”Indispensable en MP2I pour l’optimisation et la représentation bas niveau.
- Opérateurs :
- ET bit à bit :
& - OU inclusif bit à bit :
| - OU exclusif (XOR) :
^ - Complément à un (NON) :
~ - Décalage à gauche :
<<(Attention : si pas de dépassement) - Décalage à droite :
>>(Arithmétique pour les signés, logique pour les non signés).
- ET bit à bit :
Piège : Les décalages d’un nombre de bits supérieur ou égal à la largeur du type (en bits) constituent un comportement indéfini en C.
4. Complexité et Structures de données classiques
Section titled “4. Complexité et Structures de données classiques”A. Tableaux dynamiques (Vecteurs)
Section titled “A. Tableaux dynamiques (Vecteurs)”Un tableau dynamique double sa capacité (capacity) dès que le nombre d’éléments (size) atteint cette dernière.
- Théorème (Complexité amortie) : L’insertion de éléments dans un tableau dynamique vide se fait en un temps total , soit un coût amorti de par insertion.
B. Listes chaînées
Section titled “B. Listes chaînées”Une liste simplement chaînée est définie inductivement :
struct maillon { int valeur; struct maillon *suivant;};| Opération | Tableau statique/dynamique | Liste chaînée |
|---|---|---|
| Accès au -ème élément | ||
| Insertion en tête | ||
| Insertion après un pointeur |
5. Pièges et Erreurs Classiques en C (Résumé MP2I)
Section titled “5. Pièges et Erreurs Classiques en C (Résumé MP2I)”- Déréférencement de pointeur pendu (dangling pointer) : Pointer vers une variable locale dont la portée est dépassée (pile).
- Dépassement de tampon (buffer overflow) : Écrire au-delà des limites d’un tableau alloué.
- Pointeurs non initialisés : Un pointeur local non initialisé contient une valeur arbitraire (adresse poubelle). Le déréférencer mène à un Segmentation Fault.
- Erreur de type dans
sizeof:sizeof(ptr)donne la taille du pointeur (4 ou 8 octets), et non la taille du bloc pointé.