Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

النسخ العميق (Deep Copy)

جزء من قسم البرمجة كائنية التوجه في رحلة C على Coddy. الدرس 15 من 61.

عندما تُسنِد بنيةً إلى أخرى في C، تحصل على نسخة سطحية: يتم نسخ all الحقول بايتًا ببايت. يعمل هذا بشكل جيد مع القيم البسيطة مثل الأعداد الصحيحة، لكنه يسبب مشكلة مع المؤشرات: إذ تنتهي البنيتان إلى الإشارة إلى الذاكرة نفسها.

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

Person alice = {"Alice", 30};
Person copy = alice;  // نسخة سطحية!
// كلا من alice.name و copy.name يشيران إلى نفس السلسلة

إذا أجريت free لأحدهما، يصبح الآخر غير صالح. وإذا عدّلت السلسلة النصية من خلال أحدهما، فسيرى كلاهما التغيير. نادرًا ما يكون هذا ما تريده.

تخصّص عملية deep copy ذاكرة جديدة لأعضاء المؤشرات وتنسخ البيانات actual:

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

الآن يمتلك كل كائن سلسلته النصية الخاصة. يمكنك تعديل إحداهما أو تحريرها دون التأثير في الأخرى. النمط واضح ومباشر: لكل عضو مؤشّر، خصّص ذاكرة جديدة وانسخ المحتويات، وليس العنوان فقط.

challenge icon

التحدي

سهل

لنبنِ وحدة Student توضّح نمط النسخ العميق. ستنشئ دالة استنساخ تنتج نسخة مستقلة تمامًا من كائن طالب: بحيث لا يؤثر تعديل الكائن الأصلي أو تحريره في النسخة المستنسخة.

ستنشئ ثلاثة ملفات:

  • student.h: Declare بنية Student ذات عضوين: char *name (سلسلة نصية مخصّصة ديناميكيًا) وint grade. Declare ثلاث functions:
    • create_student: constructor يأخذ اسمًا ودرجة، ويعيد مؤشرًا إلى Student جديد
    • clone_student: يأخذ const Student * ويعيد مؤشرًا إلى نسخة جديدة ومستقلة
    • free_student: destructor يحرّر كل الذاكرة المخصّصة بشكل صحيح
    استخدم حواجز include بالرمز STUDENT_H.
  • student.c: Implement جميع functions الثلاث. إن function clone_student هي الجزء الأساسي. يجب أن تخصّص ذاكرة fresh لكل من البنية وسلسلة الاسم، ثم تنسخ بيانات السلسلة الفعلية (وليس عنوان المؤشر فقط). يضمن ذلك امتلاك النسخة المستنسخة لذاكرتها الخاصة، المنفصلة تمامًا عن الكائن الأصلي.
  • main.c: أنشئ طالبًا، واستنسخه، واعرض information كلا الطالبين، ثم نظّف الكائنين بشكل صحيح.

ستتلقى مُدخلين: اسم الطالب (سلسلة نصية) والدرجة (عدد صحيح).

في ملفك الرئيسي، أنشئ طالبًا باستخدام القيم المقدّمة، ثم أنشئ نسخة مستنسخة من ذلك الطالب. اطبع information الكائن الأصلي والنسخة المستنسخة للتحقق من احتوائهما على البيانات نفسها. وأخيرًا، حرّر كلا الطالبين واطبع confirmation.

اطبع الناتج بهذا التنسيق:

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

على سبيل المثال، عند استخدام المُدخلين Alice و95، سيكون الناتج:

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

يضمن نمط النسخ العميق استقلال كل كائن بشكل حقيقي: إذ تمتلك النسخة المستنسخة سلسلة نصية مخصّصة خاصة بها، وليس مؤشرًا مشتركًا إلى ذاكرة الكائن الأصلي.

جرّب بنفسك

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

int main() {
    char name[100];
    int grade;
    
    // اقرأ الإدخال
    scanf("%s", name);
    scanf("%d", &grade);
    
    // TODO: أنشئ طالباً بالاسم والدرجة المقدمين
    
    // TODO: أنشئ نسخة من الطالب
    
    // TODO: Print the original student's information
    // التنسيق: "Original: {name}, Grade: {grade}"
    
    // TODO: اطبع معلومات النسخة
    // التنسيق: "Clone: {name}, Grade: {grade}"
    
    // TODO: حرر كلا الطالبين
    
    // اطبع التأكيد
    printf("Both freed\n");
    
    return 0;
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس البرمجة كائنية التوجه

تدرّب بنفسك: مترجم C عبر الإنترنت