ترجمة آلية تحت المراجعة
الميراث
المصدر الأصليقائمة تنفيذ التمرين
تُحفظ علامات هذه القائمة على هذا الجهاز والمتصفح فقط. أنشئ حسابًا مفعّلًا لحفظ إنجاز التمرين في مسارك.
الميراث
مشكلة بحاجة إلى حل
يتم تحديد فصيلة دم الشخص بواسطة أليلين (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_familyfunction 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);
}
الإرشادات التفصيلية
لست متأكدًا من كيفية الحل؟
كيفية الاختبار
عند التشغيل ./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