You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

程序退出时调用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 01:15:51