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.
Görev
KolayDerin 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 birStudentyapısı (struct) bildirin:char *name(dinamik olarak ayrılmış bir dize) veint 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— birconst Student *alan ve yeni, bağımsız bir kopyaya işaretçi döndüren fonksiyonfree_student— ayrılan tüm belleği düzgün bir şekilde serbest bırakan yıkıcı (destructor)
STUDENT_Hsembolü ile include guard kullanın.student.c: Her üç fonksiyonu da uygulayın.clone_studentfonksiyonunuz 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 freedDerin 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;
}
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
1Modüler Programlama Temelleri
Başlık DosyalarıInclude Guard'larKaynak DosyalarıStatik FonksiyonlarÖzet: Modüler Hesap Makinesi4Kapsülleme
Opaque Pointer KavramıOpaque Struct TanımlamaGetter ve Setter MetotlarıSetter Metotlarında DoğrulamaÖzet: Gizli Kutu2Nesneler ve Metotlar
Nesne Olarak Struct'lar'Self' İşaretçisiConst Doğruluğuİşaretçi vs DeğerYardımcı MetotlarÖzet: Point Manager5Proje: Basit Banka Hesabı
Proje KurulumuHesabın Oluşturulması3Nesne Yaşam Döngüsü
Constructor DeseniDestructor DeseniStack İlklendirmeDerin KopyalamaÖzet: String Wrapper6Kompozisyon Yoluyla Kalıtım
Struct Gömmeİlk Üye KuralıÜst Üyelere ErişimUpcastingÖzet: Şekil Hiyerarşisi