CS50第5周inheritance作业:free_family函数内存泄漏问题求助
CS50第5周Inheritance作业内存泄漏问题分析
我正在完成CS50第5周的Inheritance作业,已实现create_family和free_family函数,代码可正常编译运行,其他功能正常,但通过check50检查时,发现free_family存在内存泄漏问题,无法定位原因,求分析。
// Simulate genetic inheritance of blood type #define _DEFAULT_SOURCE #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <time.h> // Each person has two parents and two alleles typedef struct person { struct person *parents[2]; char alleles[2]; } person; const int GENERATIONS = 3; const int INDENT_LENGTH = 4; person *create_family(int generations); void print_family(person *p, int generation); void free_family(person *p); char random_allele(); int main(void) { // Seed random number generator srandom(time(0)); // Create a new family with three generations person *p = create_family(GENERATIONS); // Print family tree of blood types print_family(p, 0); // Free memory free_family(p); } // Create a new individual with `generations` person *create_family(int generations) { // TODO: Allocate memory for new person person *p = malloc(sizeof(person)); // If there are still generations left to create if (generations > 1) { // Create two new parents for current person by recursively calling create_family person *parent0 = create_family(generations - 1); person *parent1 = create_family(generations - 1); // TODO: Set parent pointers for current person p->parents[0] = parent0; p->parents[1] = parent1; // TODO: Randomly assign current person's alleles based on the alleles of their parents p->alleles[0] = parent0->alleles[random() % 2]; p->alleles[1] = parent1->alleles[random() % 2]; } // If there are no generations left to create else { // TODO: Set parent pointers to NULL p->parents[0] = NULL; p->parents[1] = NULL; // TODO: Randomly assign alleles p->alleles[0] = random_allele(); p->alleles[0] = random_allele(); } // TODO: Return newly created person return p; } // Free `p` and all ancestors of `p`. void free_family(person *p) { // TODO: Handle base case if (p == NULL) { return; } // TODO: Free parents recursively free_family(p->parents[0]); free_family(p->parents[1]); // TODO: Free child free(p); } // Print each family member and their alleles. void print_family(person *p, int generation) { // Handle base case if (p == NULL) { return; } // Print indentation for (int i = 0; i < generation * INDENT_LENGTH; i++) { printf(" "); } // Print person if (generation == 0) { printf("Child (Generation %i): blood type %c%c\n", generation, p->alleles[0], p->alleles[1]); } else if (generation == 1) { printf("Parent (Generation %i): blood type %c%c\n", generation, p->alleles[0], p->alleles[1]); } else { for (int i = 0; i < generation - 2; i++) { printf("Great-"); } printf("Grandparent (Generation %i): blood type %c%c\n", generation, p->alleles[0], p->alleles[1]); } // Print parents of current generation print_family(p->parents[0], generation + 1); print_family(p->parents[1], generation + 1); } // Randomly chooses a blood type allele. char random_allele() { int r = random() % 3; if (r == 0) { return 'A'; } else if (r == 1) { return 'B'; } else { return 'O'; } }
内存泄漏原因分析
你的free_family函数逻辑本身是正确的(递归释放父母节点再释放当前节点),但内存泄漏的根源在create_family函数的内存分配错误处理缺失:
未检查
malloc返回值:
在create_family中,调用malloc(sizeof(person))后没有检查是否分配成功。如果malloc失败返回NULL,后续代码仍会执行generations > 1分支,递归创建parent0和parent1。这两个父节点的内存会被成功分配,但由于当前节点p是NULL,无法将父节点的指针保存到p->parents中,最终导致这部分内存丢失,无法被free_family释放,引发内存泄漏。额外的未初始化bug(非泄漏但需修正):
在generations == 1的分支中,你两次给p->alleles[0]赋值,完全忽略了p->alleles[1],导致该字段未初始化,可能引发后续输出异常。
修复方案
修改create_family函数,添加内存分配失败的检查和清理逻辑,同时修正alleles的赋值错误:
person *create_family(int generations) { // Allocate memory for new person person *p = malloc(sizeof(person)); // Check if malloc failed if (p == NULL) { return NULL; } // If there are still generations left to create if (generations > 1) { // Create two new parents for current person by recursively calling create_family person *parent0 = create_family(generations - 1); person *parent1 = create_family(generations - 1); // Clean up if either parent allocation failed if (parent0 == NULL || parent1 == NULL) { free_family(parent0); free_family(parent1); free(p); return NULL; } // Set parent pointers for current person p->parents[0] = parent0; p->parents[1] = parent1; // Randomly assign current person's alleles based on the alleles of their parents p->alleles[0] = parent0->alleles[random() % 2]; p->alleles[1] = parent1->alleles[random() % 2]; } // If there are no generations left to create else { // Set parent pointers to NULL p->parents[0] = NULL; p->parents[1] = NULL; // Randomly assign alleles (修正笔误) p->alleles[0] = random_allele(); p->alleles[1] = random_allele(); } // Return newly created person return p; }
这样修改后,既解决了内存泄漏问题,也修复了未初始化的字段问题,check50的检测应该就能通过了。
内容的提问来源于stack exchange,提问作者Zhen Yu
相关产品推荐
相关产品推荐

