CS50第5周Inheritance实验理解验证及内存相关问题咨询
CS50 第5周Inheritance实验理解验证与内存问题解答
你的理解验证
你的整体流程理解完全正确:
- 程序从
main函数调用create_family(GENERATIONS)启动,先为第0代的顶层个体(孩子)分配内存; - 由于
generations>1,会递归创建第1代的两位父母(P[A]、P[B]); - 处理P[A]时,继续递归创建其第2代的祖父母(GP[A]、GP[B]),直到
generations=1时,创建最基础的祖辈(父母指针设为NULL,随机分配血型); - 完成祖辈创建后,回溯设置父辈的父母指针与血型,最后完成顶层个体的血型赋值;
- 后续调用
print_family输出家族血型树,最终通过free_family释放所有动态分配的内存。
疑问解答
疑问1:person结构体的内存分配大小
person结构体的内存大小是编译期确定的固定值,和指针指向的对象无关:
- 结构体成员构成:
struct person *parents[2]:两个指针变量,在64位系统中每个指针占8字节,合计16字节;char alleles[2]:两个字符变量,每个占1字节,合计2字节;
- 加上编译器为内存对齐补充的字节(通常对齐到8字节边界,会补6字节),64位系统中
sizeof(person)通常为24字节(具体值取决于平台与编译器,但始终是固定值)。 - 注意:指针仅存储目标内存的地址,不会包含指向对象的内容,所以结构体大小只由自身成员的类型和数量决定,和指针指向的后续结构体无关。
疑问2:递归时变量p会不会导致内存丢失
不会,核心原因是递归中的p是独立的局部变量:
- 每次调用
create_family时,函数内的person *p是当前栈帧的局部变量,和其他递归层级的p完全独立; - 顶层个体分配的内存地址,会被当前递归栈帧的
p持有,随后递归创建P[A]时,新栈帧的p是另一个变量,不会覆盖顶层的内存地址; - 递归返回后,P[A]的地址会被存在
parent0变量中,最终赋值给顶层个体的parents[0],顶层个体的内存地址始终被main函数的p(或当前层级的局部变量)持有,不会丢失。
疑问3:free_family的释放逻辑与顺序
- 不会调用祖父母的父母对应的函数:因为最底层祖辈的
parents[0]和parents[1]都被设为NULL,free_family遇到p==NULL的情况会直接返回,不会继续递归; - 释放顺序是从最底层的祖辈开始,逐层向上释放:
- 调用
free_family(p->parents[0]):先递归释放P[A]的父母(GP[A]、GP[B]),再释放P[A]; - 调用
free_family(p->parents[1]):同理,先释放P[B]的父母,再释放P[B]; - 最后释放当前的顶层个体;
- 调用
- 用你的命名总结,释放顺序为:GP[A] → GP[B] → P[A] → P[B]的GP[A] → P[B]的GP[B] → P[B] → 顶层个体。
内容的提问来源于stack exchange,提问作者King Brain
相关产品推荐
相关产品推荐

