Tiefe Kopie
Teil des Abschnitts Objektorientierte Programmierung der C-Journey von Coddy. Lektion 15 von 61.
Wenn du eine Struktur einer anderen in C zuweist, erhältst du eine flache Kopie: Alle Felder werden Byte für Byte kopiert. Das funktioniert bei einfachen Werten wie Ganzzahlen problemlos, führt aber bei Zeigern zu einem Problem: Beide Strukturen zeigen letztendlich auf denselben Speicher.
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 du eine freigibst, wird die andere ungültig. Wenn du die Zeichenkette über eine von beiden änderst, sehen beide die Änderung. Das ist nur selten das, was du möchtest.
Eine tiefe Kopie reserviert neuen Speicher für Zeigermitglieder 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;
}
Jetzt besitzt jedes Objekt seine eigene Zeichenkette. Du kannst eine davon ändern oder freigeben, ohne die andere zu beeinflussen. Das Muster ist unkompliziert: Weise für jedes Zeigermitglied neuen Speicher zu und kopiere den Inhalt, nicht nur die Adresse.
Aufgabe
EinfachErstellen wir ein Student-Modul, das das Muster der tiefen Kopie demonstriert. Du erstellst eine Klonfunktion, die eine vollständig unabhängige Kopie eines Studentenobjekts erzeugt: eines Objekts, bei dem das Ändern oder Freigeben des Originals keine Auswirkungen auf den Klon hat.
Du erstellst drei Dateien:
student.h: Deklariere eineStudent-Struktur mit zwei Mitgliedern:char *name(eine dynamisch reservierte Zeichenkette) undint grade. Deklariere drei Funktionen:create_student: Konstruktor, der einen Namen und eine Note übernimmt und einen Zeiger auf einen neuen Student zurückgibtclone_student: übernimmt einenconst Student *und gibt einen Zeiger auf eine neue, unabhängige Kopie zurückfree_student: Destruktor, der den gesamten reservierten Speicher ordnungsgemäß freigibt
STUDENT_H.student.c: Implementiere alle drei Funktionen. Deine Funktionclone_studentist der entscheidende Teil. Sie muss neuen Speicher sowohl für die Struktur als auch für die Namenszeichenkette reservieren und anschließend die tatsächlichen Zeichenkettendaten kopieren (nicht nur die Zeigeradresse). Dadurch wird sichergestellt, dass der Klon vollständig eigenen Speicher besitzt, der vom Original getrennt ist.main.c: Erstelle einen Studenten, klone ihn, zeige die Informationen beider Studenten an und räume anschließend beide Objekte ordnungsgemäß auf.
Du erhältst zwei Eingaben: den Studentennamen (eine Zeichenkette) und die Note (eine Ganzzahl).
Erstelle in deiner Hauptdatei einen Studenten mit den bereitgestellten Werten und erstelle anschließend einen Klon dieses Studenten. Gib die Informationen des Originals und des Klons aus, um zu überprüfen, dass sie dieselben Daten enthalten. Gib schließlich beide Studenten frei und gib eine Bestätigung aus.
Gib die Ausgabe in diesem Format aus:
Original: {name}, Grade: {grade}
Clone: {name}, Grade: {grade}
Both freedBei den Eingaben Alice und 95 würde die Ausgabe beispielsweise folgendermaßen aussehen:
Original: Alice, Grade: 95
Clone: Alice, Grade: 95
Both freedDas Muster der tiefen Kopie stellt sicher, dass jedes Objekt wirklich unabhängig ist: Der Klon besitzt seine eigene reservierte Zeichenkette und keinen gemeinsam genutzten Zeiger auf den Speicher des Originals.
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: Print the original student's information
// Format: "Original: {name}, Grade: {grade}"
// TODO: Gib die Informationen des Klons aus
// Format: "Clone: {name}, Grade: {grade}"
// TODO: Gib beide Studenten frei
// 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 Objektorientierte Programmierung
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-ImplementierungRechteck-ImplementierungPolymorphe VerwendungShape-ContainerÜbe selbstständig: Online-C-Compiler