Menu
Coddy logo textTech

Derin Kopyalama

Coddy'nin C Journey'sinin Object Oriented Programming bölümünün bir parçası — ders 15 / 61.

C'de bir struct'ı diğerine atadığınızda, bir yüzeysel kopya (shallow copy) elde edersiniz—tüm alanlar bayt bayt (byte-for-byte) kopyalanır. Bu, tam sayılar (integers) gibi basit değerler için sorunsuz çalışır, ancak işaretçiler (pointers) ile ilgili bir sorun yaratır: her iki struct da sonuçta aynı belleği işaret eder.

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

Person alice = {"Alice", 30};
Person copy = alice;  // Sığ kopya!
// Hem alice.name hem de copy.name AYNI dizeye işaret eder

Birini serbest bırakırsanız diğeri geçersiz hale gelir. Dizeyi biri üzerinden değiştirirseniz, her ikisi de değişikliği görür. Bu nadiren istediğiniz bir şeydir.

Bir derin kopyalama (deep copy), işaretçi üyeleri için yeni bellek ayırır ve gerçek veriyi kopyalar:

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;
}

Artık her nesne kendi dizesine sahiptir. Birini, diğerini etkilemeden değiştirebilir veya serbest bırakabilirsiniz. Yöntem basittir: her işaretçi üyesi için yeni bellek ayırın ve sadece adresi değil, içeriği kopyalayın.

challenge icon

Görev

Kolay

Derin kopya (deep copy) desenini gösteren bir Student modülü oluşturalım. Bir öğrenci nesnesinin tamamen bağımsız bir kopyasını üreten bir kopyalama fonksiyonu oluşturacaksınız; öyle ki orijinali değiştirmek veya serbest bırakmak kopya üzerinde hiçbir etkiye sahip olmayacak.

Üç dosya oluşturacaksınız:

  • student.h: İki üyeye sahip bir Student yapısı (struct) bildirin: char *name (dinamik olarak ayrılmış bir dize) ve int grade. Üç fonksiyon bildirin:
    • create_student — bir isim ve not alan, yeni bir Student nesnesine işaretçi döndüren yapıcı (constructor)
    • clone_student — bir const Student * alan ve yeni, bağımsız bir kopyaya işaretçi döndüren fonksiyon
    • free_student — ayrılan tüm belleği düzgün bir şekilde serbest bırakan yıkıcı (destructor)
    STUDENT_H sembolü ile include guard kullanın.
  • student.c: Her üç fonksiyonu da uygulayın. clone_student fonksiyonunuz anahtar noktadır; hem yapı hem de isim dizesi için taze bellek ayırmalı, ardından gerçek dize verisini kopyalamalıdır (sadece işaretçi adresini değil). Bu, kopyanın orijinalden tamamen ayrı kendi belleğine sahip olmasını sağlar.
  • main.c: Bir öğrenci oluşturun, onu kopyalayın, her iki öğrencinin bilgilerini görüntüleyin, ardından her iki nesneyi de düzgün bir şekilde temizleyin.

İki girdi alacaksınız: öğrenci adı (bir dize) ve not (bir tam sayı).

Ana dosyanızda, sağlanan değerlerle bir öğrenci oluşturun, ardından o öğrencinin bir kopyasını oluşturun. Aynı verileri içerdiklerini doğrulamak için hem orijinalin hem de kopyanın bilgilerini yazdırın. Son olarak, her iki öğrenciyi de serbest bırakın ve bir onay mesajı yazdırın.

Çıktıyı şu formatta yazdırın:

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

Örneğin, Alice ve 95 girdileriyle çıktı şöyle olacaktır:

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

Derin kopya deseni, her nesnenin gerçekten bağımsız olmasını sağlar; kopya, orijinalin belleğine paylaşılan bir işaretçiye değil, kendi ayrılmış dizesine sahiptir.

Kopya kağıdı

C dilinde bir yapıyı (struct) diğerine atadığınızda, bir yüzeysel kopya (shallow copy) elde edersiniz; tüm alanlar bayt bayt kopyalanır. İşaretçiler (pointers) söz konusu olduğunda, her iki yapı da aynı bellek adresini işaret eder:

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

Person alice = {"Alice", 30};
Person copy = alice;  // Shallow copy!
// Hem alice.name hem de copy.name AYNI dizgeyi (string) işaret eder

Bir derin kopya (deep copy), işaretçi üyeler için yeni bellek ayırır ve gerçek veriyi kopyalar:

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;
}

Derin kopya deseni: her bir işaretçi üye için yeni bellek ayırın ve sadece adresi değil, içeriği kopyalayın. Bu, her nesnenin kendi belleğine sahip olmasını ve bağımsız olarak değiştirilebilmesini veya serbest bırakılabilmesini sağlar.

Kendin dene

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

int main() {
    char name[100];
    int grade;
    
    // Girdiyi oku
    scanf("%s", name);
    scanf("%d", &grade);
    
    // TODO: Sağlanan name ve grade ile bir öğrenci oluşturun
    
    // TODO: Öğrencinin bir kopyasını (clone) oluşturun
    
    // TODO: Orijinal öğrencinin bilgilerini yazdırın
    // Format: "Original: {name}, Grade: {grade}"
    
    // TODO: Kopyanın (clone) bilgilerini yazdırın
    // Format: "Clone: {name}, Grade: {grade}"
    
    // TODO: Her iki öğrenciyi de serbest bırakın (free)
    
    // Onay mesajını yazdır
    printf("Both freed\n");
    
    return 0;
}
quiz iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

Object Oriented Programming bölümündeki tüm dersler