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

为何无法释放内含指针的结构体指针数组?内存释放问题求解

问题分析与修正方案

原代码的内存释放逻辑完全错误,先逐个拆解你遇到的三个错误原因:

  1. 保留LINE A和LINE B时触发heap-use-after-free:ex是通过一次malloc(10 * sizeof(str))分配的连续结构体数组,ex+a只是数组中第a个元素的地址,并非单独用malloc分配的独立指针。第一次循环free(ex+0)后,这块内存已经被操作系统回收,后续循环访问ex+a属于访问已释放的堆内存,直接触发报错。
  2. 移除LINE A保留LINE B时触发attempting free on non-malloced address:ex+a从来不是malloc直接返回的地址,强行free自然会被检测到非法释放。
  3. 移除LINE B保留LINE A时触发内存泄漏:只释放了每个结构体内部的s指针,但整个结构体数组ex的内存块没有被释放,属于遗漏的内存泄漏。

正确的内存释放步骤

  • 先循环遍历结构体数组,逐个释放每个结构体内部的s指针(保留原LINE A)
  • 循环结束后,一次性释放整个结构体数组的内存块(替换掉循环里的LINE B,改成free(ex))

修正后的完整代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct strs {
    char* s;
} str;

int main(int argc, char* argv[argc + 1]) {
    // 检查命令行参数是否足够
    if (argc < 2) {
        fprintf(stderr, "请传入文件名作为参数\n");
        return 1;
    }

    FILE* fp = fopen(argv[1], "r");
    // 检查文件是否成功打开
    if (fp == NULL) {
        perror("文件打开失败");
        return 1;
    }
    
    // 分配结构体数组
    str* ex = malloc(10 * sizeof(str));
    if (ex == NULL) {
        perror("结构体数组分配失败");
        fclose(fp);
        return 1;
    }

    // 为每个结构体的s分配内存
    for (int a = 0; a < 10; a++) {
        // 分配10个char,包括终止符,所以最多存9个有效字符
        ex[a].s = malloc(10 * sizeof(char));
        if (ex[a].s == NULL) {
            perror("字符串内存分配失败");
            // 分配失败时要释放已分配的内存,避免泄漏
            for (int b = 0; b < a; b++) {
                free(ex[b].s);
            }
            free(ex);
            fclose(fp);
            return 1;
        }
    }

    // 读取字符串,限制长度为9,防止缓冲区溢出
    for (int a = 0; a < 10; a++) {
        if (fscanf(fp, "%9s", ex[a].s) != 1) {
            fprintf(stderr, "读取第%d个字符串失败\n", a+1);
            // 读取失败也要清理已分配的内存
            for (int b = 0; b < 10; b++) {
                free(ex[b].s);
            }
            free(ex);
            fclose(fp);
            return 1;
        }
    }

    // 打印字符串
    for (int a = 0; a < 10; a++) {
        printf("%s ", ex[a].s);
    }
    printf("\n");

    // 正确释放内存:先释放每个s,再释放整个结构体数组
    for (int a = 0; a < 10; a++) {
        free(ex[a].s); // 保留原LINE A的逻辑,这里用数组下标更清晰
    }
    free(ex); // 替换原LINE B的循环释放,改为一次性释放整个数组

    fclose(fp);
    return 0;
}

额外注意事项

  • 必须检查所有malloc的返回值,避免空指针访问
  • 打开文件后一定要检查fp是否为NULL,处理文件打开失败的情况
  • fscanf使用%9s而不是%s,因为每个s只分配了10个字节(包含字符串终止符\0),限制长度可以防止输入过长导致缓冲区溢出
  • 任何错误退出的分支都要清理已分配的内存,避免内存泄漏

内容的提问来源于stack exchange,提问作者FBYSkitty

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 15:57:49