Menu
Coddy logo textTech

Copie profonde

Fait partie de la section Object Oriented Programming du Journey C de Coddy — leçon 15 sur 61.

Lorsque vous affectez une structure à une autre en C, vous obtenez une copie superficielle : tous les champs sont copiés octet par octet. Cela fonctionne bien pour les valeurs simples comme les entiers, mais pose un problème avec les pointeurs : les deux structures finissent par pointer vers la même mémoire.

typedef struct {
    char *name;
    int age;
} Person;

Person alice = {"Alice", 30};
Person copy = alice;  // Copie superficielle !
// alice.name et copy.name pointent tous deux vers la MÊME chaîne

Si vous en libérez un, l'autre devient invalide. Si vous modifiez la chaîne via l'un d'eux, les deux voient le changement. C'est rarement ce que vous voulez.

Une copie profonde alloue une nouvelle mémoire pour les membres pointeurs et copie les données réelles :

Person *clone_person(const Person *original) {
    Person *copy = malloc(sizeof(Person));
    copy->name = malloc(strlen(original->name) + 1);
    strcpy(copy->name, original->name);
    copy->age = original->age;
    return copy;
}

Désormais, chaque objet possède sa propre chaîne de caractères. Vous pouvez en modifier ou en libérer une sans affecter l'autre. Le schéma est simple : pour chaque membre pointeur, allouez une nouvelle zone mémoire et copiez le contenu — et non pas seulement l'adresse.

challenge icon

Défi

Facile

Construisons un module Student qui illustre le modèle de copie profonde (deep copy). Vous allez créer une fonction de clonage qui produit une copie complètement indépendante d'un objet étudiant — une copie où la modification ou la libération de l'original n'a aucun effet sur le clone.

Vous allez créer trois fichiers :

  • student.h : Déclarez une structure Student avec deux membres : char *name (une chaîne de caractères allouée dynamiquement) et int grade. Déclarez trois fonctions :
    • create_student — constructeur qui prend un nom et une note, et retourne un pointeur vers un nouveau Student
    • clone_student — prend un const Student * et retourne un pointeur vers une nouvelle copie indépendante
    • free_student — destructeur qui libère correctement toute la mémoire allouée
    Utilisez des gardes d'inclusion avec le symbole STUDENT_H.
  • student.c : Implémentez les trois fonctions. Votre fonction clone_student est la clé — elle doit allouer de la mémoire fraîche pour la structure et pour la chaîne de caractères du nom, puis copier les données réelles de la chaîne (pas seulement l'adresse du pointeur). Cela garantit que le clone possède sa propre mémoire, complètement séparée de l'original.
  • main.c : Créez un étudiant, clonez-le, affichez les informations des deux étudiants, puis nettoyez correctement les deux objets.

Vous recevrez deux entrées : le nom de l'étudiant (une chaîne de caractères) et la note (un entier).

Dans votre fichier principal, créez un étudiant avec les valeurs fournies, puis créez un clone de cet étudiant. Affichez les informations de l'original et du clone pour vérifier qu'ils contiennent les mêmes données. Enfin, libérez les deux étudiants et affichez une confirmation.

Affichez la sortie dans ce format :

Original: {name}, Grade: {grade}
Clone: {name}, Grade: {grade}
Both freed

Par exemple, avec les entrées Alice et 95, la sortie serait :

Original: Alice, Grade: 95
Clone: Alice, Grade: 95
Both freed

Le modèle de copie profonde garantit que chaque objet est véritablement indépendant — le clone possède sa propre chaîne allouée, et non un pointeur partagé vers la mémoire de l'original.

Aide-mémoire

Lorsque vous assignez une structure à une autre en C, vous obtenez une copie superficielle (shallow copy)—tous les champs sont copiés octet par octet. Avec les pointeurs, les deux structures finissent par pointer vers la même zone mémoire :

typedef struct {
    char *name;
    int age;
} Person;

Person alice = {"Alice", 30};
Person copy = alice;  // Copie superficielle !
// alice.name et copy.name pointent tous deux vers la MÊME chaîne

Une copie profonde (deep copy) alloue de la nouvelle mémoire pour les membres pointeurs et copie les données réelles :

Person *clone_person(const Person *original) {
    Person *copy = malloc(sizeof(Person));
    copy->name = malloc(strlen(original->name) + 1);
    strcpy(copy->name, original->name);
    copy->age = original->age;
    return copy;
}

Le modèle de copie profonde : pour chaque membre pointeur, allouez de la mémoire neuve et copiez le contenu—pas seulement l'adresse. Cela garantit que chaque objet possède sa propre mémoire et peut être modifié ou libéré indépendamment.

Essayez vous-même

#include <stdio.h>
#include <stdlib.h>
#include "student.h"

int main() {
    char name[100];
    int grade;
    
    // Lire l'entrée
    scanf("%s", name);
    scanf("%d", &grade);
    
    // TODO: Créer un étudiant avec le nom et la note fournis
    
    // TODO: Créer un clone de l'étudiant
    
    // TODO: Afficher les informations de l'étudiant original
    // Format: "Original: {name}, Grade: {grade}"
    
    // TODO: Afficher les informations du clone
    // Format: "Clone: {name}, Grade: {grade}"
    
    // TODO: Libérer les deux étudiants
    
    // Afficher la confirmation
    printf("Both freed\n");
    
    return 0;
}
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Object Oriented Programming