为何无法释放内含指针的结构体指针数组?内存释放问题求解
问题分析与修正方案
原代码的内存释放逻辑完全错误,先逐个拆解你遇到的三个错误原因:
- 保留LINE A和LINE B时触发
heap-use-after-free:ex是通过一次malloc(10 * sizeof(str))分配的连续结构体数组,ex+a只是数组中第a个元素的地址,并非单独用malloc分配的独立指针。第一次循环free(ex+0)后,这块内存已经被操作系统回收,后续循环访问ex+a属于访问已释放的堆内存,直接触发报错。 - 移除LINE A保留LINE B时触发
attempting free on non-malloced address:ex+a从来不是malloc直接返回的地址,强行free自然会被检测到非法释放。 - 移除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
相关产品推荐
相关产品推荐

