Menu
Coddy logo textTech

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.

challenge icon

Aufgabe

Einfach

Lassen 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 eine Student-Struktur mit zwei Elementen: char *name (ein dynamisch zugewiesener String) und int grade. Deklarieren Sie drei Funktionen:
    • create_student — Konstruktor, der einen Namen und eine Note entgegennimmt und einen Zeiger auf einen neuen Studenten zurückgibt
    • clone_student — nimmt einen const Student * entgegen und gibt einen Zeiger auf eine neue, unabhängige Kopie zurück
    • free_student — Destruktor, der den gesamten zugewiesenen Speicher ordnungsgemäß freigibt
    Verwenden Sie Include-Guards mit dem Symbol STUDENT_H.
  • student.c: Implementieren Sie alle drei Funktionen. Ihre clone_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 freed

Zum Beispiel wäre bei den Eingaben Alice und 95 die Ausgabe:

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

Das 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;
}
quiz iconTeste dich selbst

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