Skip to main content

实验 5:继承 - CS50x 2023

模拟一个家庭中血型的遗传。

$ ./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


背景

人的血型由两个等位基因(即基因的不同形式)决定。三种可能的等位基因是 A、B 和 O,每个人都有两个(可能相同,可能不同)。孩子的父母会各自随机将他们的一个血型等位基因传递给孩子。因此,可能的血型组合有:OO、OA、OB、AO、AA、AB、BO、BA 和 BB。

例如,如果父母一方的血型为 AO,另一方的血型为 BB,那么孩子的可能血型为 AB 和 OB,取决于从父母双方获得的等位基因。 类似地,如果父母一方的血型为 AO,另一方的血型为 OB,那么孩子的可能血型有 AO、OB、AB 和 OO。

开始

打开 VS Code

首先点击终端窗口,然后单独执行 cd。您会发现提示符类似于以下内容。

单击该终端窗口内部,然后执行

wget https://cdn.cs50.net/2022/fall/labs/5/inheritance.zip

然后按回车键,以便在您的 codespace 中下载名为 inheritance.zip 的 ZIP 文件。 请注意不要忽略 wget 和 URL 之间的空格,以及任何其他字符!

现在执行

创建一个名为 inheritance 的文件夹。 您不再需要 ZIP 文件,因此可以执行

并在提示符下输入“y”,然后按回车键删除下载的 ZIP 文件。

现在输入

然后按回车键进入该目录。 现在您的提示符应该类似于以下内容。

如果遇到问题,请重复以上步骤,看看能否找到出错的地方!

理解

查看 inheritance.c 中的分发代码。

注意名为 person 的类型定义。 每个人都有一个包含两个 parents 的数组,每个 parents 都是指向另一个 person 结构体的指针。 每个人还有一个包含两个 alleles 的数组,每个 alleles 都是 char 类型('A''B''O')。

现在,看一下 main 函数。 该函数首先“播种”(即为随机数生成器提供初始输入),我们稍后将使用它来生成随机等位基因。 然后,main 函数调用 create_family 函数来模拟创建 3 代家庭(即一个人、其父母和祖父母)的 person 结构体。 然后我们调用 print_family 来打印出每个家庭成员及其血型。 最后,该函数调用 free_family 来释放之前使用 malloc 分配的内存。

create_familyfree_family 函数留给您编写!

实现细节

完成 inheritance.c 的实现,使其能够创建一个指定代数的家庭,并将血型等位基因分配给每个家庭成员。 最老一代将随机分配等位基因。

  • create_family 函数接受一个整数 (generations) 作为输入,应该为该代数的家庭的每个成员分配(通过 malloc)一个 person 结构体,并返回指向最年轻一代 person 结构体的指针。
    • 例如,create_family(3) 应该返回一个指向拥有两个父母的 person 结构体的指针,其中每个父母也有两个父母。
    • 每个 person 结构体都应该分配有 alleles。 最老一代应该随机选择等位基因(通过调用 random_allele 函数),而年轻一代应该从父母双方各继承一个等位基因(随机选择)。
    • 最老一代应该将 parents 都设置为 NULL,而年轻一代的 parents 应该是一个包含两个指针的数组,每个指针分别指向其父母。

我们将 create_family 函数分解为几个 TODO 项,供您完成。

  • 首先,您应该为新的 person 结构体分配内存。 回想一下,可以使用 malloc 来分配内存,并使用 sizeof(person) 来获取需要分配的字节数。
  • 接下来,我们包含了一个条件来检查 generations > 1
    • 如果 generations > 1,那么还有更多代需要分配。 我们已经通过递归调用 create_family 创建了两个新的 parents,分别是 parent0parent1。 然后,您的 create_family 函数应该设置您创建的新 person 结构体的父指针。 最后,从父母双方随机选择一个等位基因来分配新 person 结构体的两个 alleles
    • 否则(如果 generations == 1),那么该 person 结构体将没有父节点数据。 该 person 结构体的 parents 都应设置为 NULL,并且每个 allele 都应随机生成。
  • 最后,您的函数应该返回已分配的 person 结构体的指针。

free_family 函数应该接受指向 person 结构体的指针作为输入,释放该结构体的内存,然后递归地释放其所有祖先的内存。

  • 由于这是一个递归函数,您应该首先处理基本情况。如果函数的输入是 NULL,那么就没有任何内容需要释放,因此您的函数可以立即返回。
  • 否则,在free这个子节点之前,您应该递归地free其父母节点。

演练

提示

  • 您可以使用 rand() 函数来随机分配等位基因。此函数返回一个介于 0RAND_MAX(即 2147483647)之间的整数。
    • 特别是,要生成一个伪随机数,该数是 01,您可以使用表达式 rand() % 2
  • 请记住,要为特定的人分配内存,我们可以使用 malloc(n),它接受一个大小参数,并分配 n 字节的内存。
  • 请记住,要通过指针访问变量,可以使用箭头符号。
    • 例如,如果 p 是指向某个人的指针,那么指向此人的第一个父节点的指针可以通过 p->parents[0] 访问。

不确定如何解决?

如何测试你的代码

运行 ./inheritance 后,您的程序应遵守背景中描述的规则。孩子应该有两个等位基因,分别来自其父母。父母也应该各有两个等位基因,分别来自他们的父母。

例如,在下面的示例中,第 0 代的孩子从第 1 代的两位父母处分别获得一个 O 等位基因。第一位父母从两位祖父母处分别获得 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 评估代码的正确性。但一定要自己编译和测试它!

check50 cs50/labs/2023/x/inheritance

执行以下命令以使用 style50 评估代码的风格。

如何提交

在您的终端中,执行以下命令以提交您的工作。

submit50 cs50/labs/2023/x/inheritance