تمرين من المصدر الأصلي · تطبيق عملي

الميراث

استخدم الشرح العربي للفهم، واعتمد صفحة CS50 الأصلية مرجعًا نهائيًا للمواصفات والتسليم.

جلسة دراسة مقترحة: حتى 60 دقيقةالجهد الكلي التقريبي: 120 دقيقة · أكمل من حيث توقفت لاحقًا.Week 5
محاور هذه الخطوة
  • القوائم المتصلة
  • الجداول المبعثرة
  • الأشجار
  • المؤشرات

ترجمة آلية تحت المراجعة

الميراث

المصدر الأصلي

قائمة تنفيذ التمرين

تُحفظ علامات هذه القائمة على هذا الجهاز والمتصفح فقط. أنشئ حسابًا مفعّلًا لحفظ إنجاز التمرين في مسارك.

الميراث

محتوى خارجي من YouTube

لن نتصل بهذه الخدمة قبل موافقتك. يمكنك فتح المصدر في نافذة مستقلة بدل تحميله هنا.

فتح المصدر

مشكلة بحاجة إلى حل

يتم تحديد فصيلة دم الشخص بواسطة أليلين (i.e.، أشكال مختلفة من الجين). الأليلات الثلاثة المحتملة هي A وB وO، ولكل شخص اثنان منها (ربما نفس الشيء، وربما مختلفين). يقوم كل من والدي الطفل بتمرير أحد أليلات فصيلة الدم بشكل عشوائي إلى طفله. مجموعات فصائل الدم المحتملة هي: OO، وOA، وOB، وAO، وAA، وAB، وBO، وBA، وBB.

على سبيل المثال، إذا كان أحد الوالدين لديه فصيلة دم AO وكان الوالد الآخر لديه فصيلة دم BB، فإن فصائل الدم المحتملة للطفل ستكون AB وOB، اعتمادًا على الأليل الذي تم تلقيه من كل والد. وبالمثل، إذا كان أحد الوالدين لديه فصيلة دم AO والآخر OB، فإن فصائل الدم المحتملة للطفل ستكون AO وOB وAB وOO.

في ملف يسمى inheritance.c في مجلد يسمى inheritance، محاكاة وراثة فصائل الدم لكل فرد من أفراد الأسرة.

تجريبي

رمز التوزيع

بالنسبة لهذه المشكلة، ستقوم بتوسيع وظيفة الشيفرة المقدمة لك من قبل موظفي CS50.

قم بتنزيل كود التوزيع

قم بتسجيل الدخول cs50.dev، انقر على نافذتك الطرفية، وقم بالتنفيذ cd بمفرده. يجب أن تجد أن مطالبة النافذة الطرفية الخاصة بك تشبه ما يلي:

$

التنفيذ التالي

wget https://cdn.cs50.net/2026/x/psets/5/inheritance.zip

من أجل تنزيل ملف ZIP يسمى inheritance.zip في مساحة الشيفرة الخاصة بك.

ثم نفذ

unzip inheritance.zip

لإنشاء مجلد يسمى inheritance. لم تعد بحاجة إلى ملف ZIP، حتى تتمكن من التنفيذ

rm inheritance.zip

ثم قم بالرد بـ "y" متبوعًا بـ Enter عند المطالبة لإزالة ملف ZIP الذي قمت بتنزيله.

الآن اكتب

cd inheritance

متبوعًا بـ Enter للانتقال إلى (i.e.، open) هذا الدليل. يجب أن تشبه مطالبتك الآن ما يلي.

inheritance/ $

تنفيذ ls بمفرده، ويجب أن ترى وترى الملف المسمى inheritance.c.

إذا واجهت أي مشكلة، فاتبع نفس الخطوات مرة أخرى لترى ما إذا كان بإمكانك تحديد الخطأ الذي ارتكبته!

تفاصيل التنفيذ

أكمل تنفيذ inheritance.c، بحيث ينشئ عائلة ذات حجم جيل محدد ويعين أليلات فصيلة الدم لكل فرد من أفراد الأسرة. سيتم تخصيص أليلات للجيل الأقدم بشكل عشوائي.

  • ال يتم استخدام الدالة create_family function takes an integer (generations) كمدخل ويجب تخصيصه (كما هو موضح عبر malloc) واحد person لكل فرد من أفراد الأسرة من هذا العدد من الأجيال، مع إرجاع المؤشر إلى person في الجيل الأصغر. يجب أن يقوم
    • على سبيل المثال، create_family(3) بإرجاع مؤشر إلى شخص لديه أبوين، حيث يكون لكل والد أيضًا أبوين.
    • لكل منهما person ينبغي أن يكون alleles المخصصة لهم. يجب أن يكون لدى الجيل الأقدم أليلات تم اختيارها عشوائيًا (كما هو الحال من خلال استدعاء random_allele )، ويجب أن ترث الأجيال الشابة أليلًا واحدًا (يتم اختياره عشوائيًا) من كل والد.
    • لكل منهما person ينبغي أن يكون parents المخصصة لهم. يجب أن يتمتع الجيل الأقدم بكليهما تم ضبط parents على NULL، والأجيال الشابة يجب أن تمتلك ذلك parents عبارة عن مصفوفة من مؤشرين، يشير كل منهما إلى أصل مختلف.

تلميحات

فهم الشيفرة الموجود inheritance.c

ألق نظرة على كود التوزيع في inheritance.c.

لاحظ تعريف نوع يسمى person. كل شخص لديه مجموعة من اثنين parents، كل منها مؤشر للآخر person البنية. كل شخص لديه أيضا مجموعة من اثنين alleles، كل منها عبارة عن char (إما وظيفة 'A', 'B'، أو 'O').

// Each person has two parents and two alleles
typedef struct person
{
    struct person *parents[2];
    char alleles[2];
}
person;

الآن، ألق نظرة على main . تبدأ الوظيفة عن طريق "البذر" (i.e.، مما يوفر بعض المدخلات الأولية لـ) مولد أرقام عشوائي، والذي سنستخدمه لاحقًا لإنشاء أليلات عشوائية. تقوم الدالة

// Seed random number generator
srandom(time(0));

ال يتم استخدام الدالة main باستدعاء الدالة وظيفة create_family لمحاكاة إنشاء person مكوّن لعائلة مكونة من 3 أجيال (i.e. شخص ووالديه وأجداده).

// Create a new family with three generations
person *p = create_family(GENERATIONS);

ثم نتصل print_family لطباعة كل فرد من أفراد العائلة وفصائل دمهم.

// Print family tree of blood types
print_family(p, 0);

أخيرًا، يتم استدعاء الوظيفة free_family إلى free أي ذاكرة تم تخصيصها مسبقًا وظائف malloc.

// Free memory
free_family(p);

ال يتم استخدام الدالة create_family و free_family متروكة لك لتكتبها! يجب أن تقوم الدالة

أكمل وظيفة create_family

ال يتم استخدام الدالة create_family بإرجاع مؤشر إلى ملف person الذي ورث فصيلة دمه من عدد generations تم تقديمه كمدخل.

  • لاحظ أولاً أن هذه المشكلة تمثل فرصة جيدة للتكرار.
    • لتحديد فصيلة دم الشخص الحالي، عليك أولاً تحديد فصائل دم والديه.
    • لتحديد فصائل دم هؤلاء الآباء، يجب عليك تحديدها أولاً بهم فصائل دم الوالدين. وهكذا حتى تصل إلى الجيل الأخير الذي ترغب في محاكاته.

لحل هذه المشكلة، ستجد عدة مهام في كود التوزيع.

أولاً، يجب عليك تخصيص ذاكرة لشخص جديد. أذكر أنه يمكنك استخدام malloc لتخصيص الذاكرة، و sizeof(person) للحصول على عدد البايتات المراد تخصيصها.

// Allocate memory for new person
person *new_person = malloc(sizeof(person));

بعد ذلك، يجب عليك التحقق مما إذا كان لا يزال هناك أجيال متبقية لإنشاء: أي ما إذا كان generations > 1.

إذا generations > 1، إذن هناك المزيد من الأجيال التي لا تزال بحاجة إلى التخصيص. لقد أنشأنا بالفعل والدين جديدين، parent0 و parent1، عن طريق الاتصال بشكل متكرر create_family. لك create_family بعد ذلك بتعيين المؤشرات الأصلية للشخص الجديد الذي قمت بإنشائه. وأخيرا، تعيين كليهما alleles للشخص الجديد عن طريق اختيار أليل واحد من كل والد بشكل عشوائي.

  • تذكر، للوصول إلى متغير عبر المؤشر، يمكنك استخدام علامة السهم. على سبيل المثال، إذا p هو مؤشر لشخص ما، ومن ثم يمكن الوصول إلى مؤشر الوالد الأول لهذا الشخص عن طريق p->parents[0].
  • قد تجد وظيفة random() مفيدة لتعيين الأليلات بشكل عشوائي. ترجع هذه الدالة عددًا صحيحًا بين 0 و RAND_MAX، أو 32767. على وجه الخصوص، لإنشاء رقم عشوائي زائف إما 0 أو 1، يمكنك استخدام التعبير random() % 2.
// Create two new parents for current person by recursively calling create_family
person *parent0 = create_family(generations - 1);
person *parent1 = create_family(generations - 1);

// Set parent pointers for current person
new_person->parents[0] = parent0;
new_person->parents[1] = parent1;

// Randomly assign current person's alleles based on the alleles of their parents
new_person->alleles[0] = parent0->alleles[random() % 2];
new_person->alleles[1] = parent1->alleles[random() % 2];

لنفترض أنه لم يعد هناك أجيال أخرى لمحاكاتها. هذا هو، generations == 1. إذا كان الأمر كذلك، فلن تكون هناك بيانات الوالدين لهذا الشخص. يجب ضبط كلا والدا الشخص الجديد على ذلك NULL، وكل منهما يجب إنشاء allele بشكل عشوائي.

// Set parent pointers to NULL
new_person->parents[0] = NULL;
new_person->parents[1] = NULL;

// Randomly assign alleles
new_person->alleles[0] = random_allele();
new_person->alleles[1] = random_allele();

أخيرًا، يجب أن تُرجع وظيفتك مؤشرًا لـ person الذي تم تخصيصه. يجب أن تقبل الدالة

// Return newly created person
return new_person;
أكمل وظيفة free_family

ال يتم استخدام الدالة free_family مؤشرًا إلى ملف a person، قم بتحرير الذاكرة لهذا الشخص، ثم قم بتحرير الذاكرة بشكل متكرر لجميع أسلافه.

  • نظرًا لأن هذه دالة متكررة، يجب عليك أولاً التعامل مع الحالة الأساسية. إذا كان الإدخال إلى الوظيفة NULL، فلا يوجد شيء يمكن تحريره، لذا يمكن لوظيفتك العودة على الفور.
  • وإلا، يجب عليك بشكل متكرر free كلا والدي الشخص من قبل freeللطفل.

ما يلي هو التلميح تمامًا، ولكن إليك كيفية القيام بذلك!

// Free `p` and all ancestors of `p`.
void free_family(person *p)
{
    // Handle base case
    if (p == NULL)
    {
        return;
    }

    // Free parents recursively
    free_family(p->parents[0]);
    free_family(p->parents[1]);

    // Free child
    free(p);
}

الإرشادات التفصيلية

محتوى خارجي من YouTube

لن نتصل بهذه الخدمة قبل موافقتك. يمكنك فتح المصدر في نافذة مستقلة بدل تحميله هنا.

فتح المصدر
لست متأكدًا من كيفية الحل؟
محتوى خارجي من YouTube

لن نتصل بهذه الخدمة قبل موافقتك. يمكنك فتح المصدر في نافذة مستقلة بدل تحميله هنا.

فتح المصدر

كيفية الاختبار

عند التشغيل ./inheritance، يجب أن يلتزم برنامجك بالقواعد الموضحة في الخلفية. يجب أن يكون لدى الطفل أليلان، واحد من كل والد. يجب أن يكون لدى كل من الوالدين أليلان، واحد من كل من الوالدين.

على سبيل المثال، في المثال أدناه، تلقى الطفل في الجيل 0 أليل O من كلا الوالدين من الجيل 1. حصل الوالد الأول على A من الجد الأول وO من الجد الثاني. وبالمثل، حصل الوالد الثاني على درجتي O وB من أجداده.

$ ./inheritance
Child (Generation 0): blood type OO
    Parent (Generation 1): blood type AO
        Grandparent (Generation 2): blood type OA
        Grandparent (Generation 2): blood type BO
    Parent (Generation 1): blood type OB
        Grandparent (Generation 2): blood type AO
        Grandparent (Generation 2): blood type BO

صحة

check50 cs50/problems/2026/x/inheritance

النمط

style50 inheritance.c

كيفية الإرسال

في جهازك الطرفي، قم بتنفيذ ما يلي لإرسال عملك، والإجابة على المطالبات التي تظهر أيضًا.

submit50 cs50/problems/2026/x/inheritance

أنهيت التطبيق؟

راجع عناصر التنفيذ أعلاه، ثم احفظ إنجازك وانتقل إلى التمرين التالي.

حفظ إنجاز التمرين

يمكنك قراءة الدورة كاملة دون حساب. يصبح حفظ التقدم متاحًا بعد تفعيل الحساب، ويبقى محفوظًا بعد انتهاء العضوية.

العودة إلى جميع التمارين