程序退出时调用free_tkt_arr()能否释放create/update_ticket中_strdup分配的内存?
问题解答:
free_tkt_arr()能否释放所有_strdup()分配的内存? 结论:当前代码无法完全释放所有内存,存在多处内存泄漏风险,具体原因和改进方案如下:
一、核心问题分析
1. create_ticket()的内存未加入数组
你在create_ticket()里创建了局部变量new_ticket,给它的字段分配内存后,没有把这个工单实例加入全局的tkt_array。这意味着这些_strdup()分配的内存地址根本没存在数组里,free_tkt_arr()遍历数组时找不到这些内存块,自然无法释放,直接造成内存泄漏。
2. update_ticket()的两处隐患
- 内存未关联到数组:如果
tmp_ticket2不是tkt_array里的元素(比如是局部变量),更新时用_strdup()分配的新内存不会被free_tkt_arr()遍历到,无法释放。 - 旧内存未释放:就算
tmp_ticket2是数组里的元素,更新时直接给status/problem/assigned_to赋值新的_strdup()结果,会覆盖原来的指针,导致旧内存块丢失,无法被释放,同样造成泄漏。
3. free_tkt_arr()的小细节
循环条件i <= tkt_count - 1等价于i < tkt_count,后者更符合C语言遍历数组的习惯,逻辑上没问题,但前者写法稍显冗余。
二、修复方案
1. 修正create_ticket(),将新工单加入数组
直接操作tkt_array里的元素,确保内存地址被存入数组:
void create_ticket() { if (tkt_count >= NUM_TICKETS) { printf("工单数量已达上限,无法创建新工单\n"); return; } struct ticket *new_ticket = &tkt_array[tkt_count]; printf("Enter your name: "); new_ticket->name = _strdup(get_input(20)); printf("Enter problem description: "); new_ticket->problem = _strdup(get_input(100)); printf("Assigned to: "); new_ticket->assigned_to = _strdup(get_input(20)); new_ticket->status = _strdup("new"); tkt_count++; }
2. 修正update_ticket(),释放旧内存并关联数组
先找到数组中对应的工单,更新前释放旧内存,再赋值新内存:
void update_ticket() { char *ptr = get_input(8); int ticket_num; sscanf_s(ptr, "%d", &ticket_num); free(ptr); // get_input分配的内存也要释放 if (ticket_num < 0 || ticket_num >= tkt_count) { printf("无效的工单编号\n"); return; } struct ticket *target_ticket = &tkt_array[ticket_num]; printf("选择更新项:1-状态 2-问题描述 3-负责人\n"); char choice = get_input(1)[0]; switch(choice) { case '1': printf("输入新状态:"); free(target_ticket->status); target_ticket->status = _strdup(get_input(20)); break; case '2': printf("输入新问题描述:"); free(target_ticket->problem); target_ticket->problem = _strdup(get_input(100)); break; case '3': printf("输入新负责人:"); free(target_ticket->assigned_to); target_ticket->assigned_to = _strdup(get_input(20)); break; default: printf("无效选择\n"); } }
注意:如果get_input()是你自己实现的、会分配内存的函数,记得释放它返回的指针,比如上面的ptr。
3. 优化free_tkt_arr(),避免野指针
简化循环条件,释放后将指针置空:
void free_tkt_arr() { for (int i = 0; i < tkt_count; i++) { free(tkt_array[i].assigned_to); tkt_array[i].assigned_to = NULL; free(tkt_array[i].name); tkt_array[i].name = NULL; free(tkt_array[i].problem); tkt_array[i].problem = NULL; free(tkt_array[i].status); tkt_array[i].status = NULL; } tkt_count = 0; }
三、额外提示
关于valgrind,其实入门没你想的难。编译时加-g参数生成调试信息,然后运行valgrind --leak-check=full ./your_program,就能看到详细的内存泄漏报告,能帮你快速定位问题,非常适合C语言内存管理的学习。
内容的提问来源于stack exchange,提问作者Andrew
相关产品推荐
相关产品推荐

