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.
Défi
FacileConstruisons 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 structureStudentavec deux membres :char *name(une chaîne de caractères allouée dynamiquement) etint grade. Déclarez trois fonctions :create_student— constructeur qui prend un nom et une note, et retourne un pointeur vers un nouveau Studentclone_student— prend unconst Student *et retourne un pointeur vers une nouvelle copie indépendantefree_student— destructeur qui libère correctement toute la mémoire allouée
STUDENT_H.student.c: Implémentez les trois fonctions. Votre fonctionclone_studentest 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 freedPar exemple, avec les entrées Alice et 95, la sortie serait :
Original: Alice, Grade: 95
Clone: Alice, Grade: 95
Both freedLe 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;
}
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
1Bases de la programmation modulaire
Fichiers d'en-têteGardes d'inclusionFichiers sourcesFonctions statiquesRécapitulatif : Calculatrice modulaire4Encapsulation
Concept des pointeurs opaquesDéfinir des structures opaquesGetters et settersValidation dans les settersRécapitulatif : La boîte secrète2Objets et méthodes
Structs comme objetsLe pointeur 'Self'Rigueur du mot-clé constPointeur vs ValeurMéthodes utilitairesRécapitulatif : Point Manager5Projet : Compte bancaire simple
Configuration du projetImplémentation du compte8Polymorphisme
Pointeurs de fonctions dans les structuresSimulation de méthodesLe concept d'interfaceImplémentation d'interfacesItération polymorphiqueRécapitulatif : Greeter11Patrons de conception en C
Patron SingletonPatron FabriquePatron ItérateurRécapitulatif : Logger Factory3Cycle de vie des objets
Pattern de constructeurPattern de destructeurInitialisation sur la pileCopie profondeRécapitulatif : String Wrapper6Héritage par composition
Imbrication de structLa règle du premier membreAccès aux membres parentsUpcastingRécapitulatif : Hiérarchie des formes9Projet : Dessinateur de formes
Aperçu du projetImplémentation du cercle