Tiefe Kopie
Teil des Abschnitts Object Oriented Programming der C-Journey von Coddy — Lektion 15 von 61.
Wenn Sie in C eine Struktur einer anderen zuweisen, erhalten Sie eine flache Kopie (shallow copy) – alle Felder werden Byte für Byte kopiert. Dies funktioniert bei einfachen Werten wie Integern einwandfrei, führt jedoch bei Pointern zu einem Problem: Beide Strukturen zeigen am Ende auf denselben Speicherbereich.
typedef struct {
char *name;
int age;
} Person;
Person alice = {"Alice", 30};
Person copy = alice; // Flache Kopie!
// Sowohl alice.name als auch copy.name zeigen auf denselben String
Wenn Sie einen freigeben, wird der andere ungültig. Wenn Sie den String über einen modifizieren, sehen beide die Änderung. Dies ist selten das, was Sie wollen.
Eine tiefe Kopie reserviert neuen Speicher für Zeiger-Elemente und kopiert die eigentlichen Daten:
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;
}
Nun besitzt jedes Objekt seinen eigenen String. Sie können einen modifizieren oder freigeben, ohne den anderen zu beeinflussen. Das Muster ist einfach: Reservieren Sie für jedes Pointer-Member neuen Speicher und kopieren Sie den Inhalt – nicht nur die Adresse.
Aufgabe
EinfachLassen Sie uns ein Student-Modul bauen, das das Deep-Copy-Muster demonstriert. Sie werden eine Klonfunktion erstellen, die eine völlig unabhängige Kopie eines Studentenobjekts erzeugt – eine, bei der das Ändern oder Freigeben des Originals keine Auswirkungen auf den Klon hat.
Sie werden drei Dateien erstellen:
student.h: Deklarieren Sie eineStudent-Struktur mit zwei Elementen:char *name(ein dynamisch zugewiesener String) undint grade. Deklarieren Sie drei Funktionen:create_student— Konstruktor, der einen Namen und eine Note entgegennimmt und einen Zeiger auf einen neuen Studenten zurückgibtclone_student— nimmt einenconst Student *entgegen und gibt einen Zeiger auf eine neue, unabhängige Kopie zurückfree_student— Destruktor, der den gesamten zugewiesenen Speicher ordnungsgemäß freigibt
STUDENT_H.student.c: Implementieren Sie alle drei Funktionen. Ihreclone_student-Funktion ist der Schlüssel – sie muss frischen Speicher sowohl für die Struktur als auch für den Namens-String zuweisen und dann die tatsächlichen String-Daten kopieren (nicht nur die Zeigeradresse). Dies stellt sicher, dass der Klon seinen eigenen Speicher besitzt, der völlig getrennt vom Original ist.main.c: Erstellen Sie einen Studenten, klonen Sie ihn, zeigen Sie die Informationen beider Studenten an und bereinigen Sie dann beide Objekte ordnungsgemäß.
Sie erhalten zwei Eingaben: den student name (einen String) und die grade (eine Ganzzahl).
Erstellen Sie in Ihrer Hauptdatei einen Studenten mit den angegebenen Werten und erstellen Sie dann einen Klon dieses Studenten. Geben Sie sowohl die Informationen des Originals als auch des Klons aus, um zu überprüfen, ob sie dieselben Daten enthalten. Geben Sie schließlich beide Studenten frei und geben Sie eine Bestätigung aus.
Geben Sie die Ausgabe in diesem Format aus:
Original: {name}, Grade: {grade}
Clone: {name}, Grade: {grade}
Both freedZum Beispiel wäre bei den Eingaben Alice und 95 die Ausgabe:
Original: Alice, Grade: 95
Clone: Alice, Grade: 95
Both freedDas Deep-Copy-Muster stellt sicher, dass jedes Objekt wirklich unabhängig ist – der Klon hat seinen eigenen zugewiesenen String, keinen gemeinsam genutzten Zeiger auf den Speicher des Originals.
Spickzettel
Wenn Sie in C ein Struct einem anderen zuweisen, erhalten Sie eine flache Kopie (shallow copy) – alle Felder werden Byte für Byte kopiert. Bei Zeigern zeigen beide Structs am Ende auf denselben Speicherbereich:
typedef struct {
char *name;
int age;
} Person;
Person alice = {"Alice", 30};
Person copy = alice; // Flache Kopie!
// Sowohl alice.name als auch copy.name zeigen auf denselben String
Eine tiefe Kopie (deep copy) reserviert neuen Speicher für Zeiger-Member und kopiert die tatsächlichen Daten:
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;
}
Das Muster der tiefen Kopie: Reservieren Sie für jedes Zeiger-Member neuen Speicher und kopieren Sie den Inhalt – nicht nur die Adresse. Dies stellt sicher, dass jedes Objekt seinen eigenen Speicher besitzt und unabhängig modifiziert oder freigegeben werden kann.
Probier es selbst
#include <stdio.h>
#include <stdlib.h>
#include "student.h"
int main() {
char name[100];
int grade;
// Eingabe lesen
scanf("%s", name);
scanf("%d", &grade);
// TODO: Erstelle einen Studenten mit dem angegebenen Namen und der Note
// TODO: Erstelle einen Klon des Studenten
// TODO: Informationen des ursprünglichen Studenten ausgeben
// Format: "Original: {name}, Grade: {grade}"
// TODO: Informationen des Klons ausgeben
// Format: "Clone: {name}, Grade: {grade}"
// TODO: Beide Studenten freigeben
// Bestätigung ausgeben
printf("Both freed\n");
return 0;
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Object Oriented Programming
1Grundlagen der modularen Programmierung
Header-DateienInclude GuardsQuelldateienStatische FunktionenWiederholung: Modularer Taschenrechner4Kapselung
Konzept der Opaque PointersOpaque Structs definierenGetter und SetterValidierung in SetternRückblick: Die geheime Box2Objekte und Methoden
Structs als ObjekteDer 'Self'-PointerConst-CorrectnessPointer vs. WertHilfsmethodenZusammenfassung: Point Manager5Projekt: Einfaches Bankkonto
Projekt-SetupImplementierung des Kontos3Objekt-Lebenszyklus
Konstruktor-MusterDestruktor-MusterStack-InitialisierungTiefe KopieRückblick: String-Wrapper6Vererbung durch Komposition
Struct-EinbettungDie First-Member-RegelZugriff auf Parent-MemberUpcastingRückblick: Formenhierarchie9Projekt: Formen-Zeichner
ProjektübersichtKreis-Implementierung