C语言单循环分配初始化存储文件数据的缓冲区
问题描述
我尝试使用底层文件描述符将文件内容读取到缓冲区中,该方法需要将文件数据逐字节存入char *类型缓冲区,完成数据解析后释放已分配的缓冲区内存。
初始实现代码如下:
static void parse_file(char path[11]) { int fd = open(path, O_RDONLY); if (fd == -1) { fprintf(stderr, "Failed to open a file '%s'", path); exit(errno); } char c; char *buffer = {0}; unsigned int i = 0; while (read(fd, &c, 1)) { buffer = malloc(sizeof(char)); // Why *buffer want work here? *buffer = c; ++buffer; ++i; } buffer = malloc(sizeof(char)); *buffer = '\0'; buffer = &buffer[0]; printf("Buffer data:\n%s\n", buffer); // Parse buffer data // ... buffer = &buffer[0]; for (unsigned int j = 0; j <= i; ++j) { free(buffer); ++buffer; } }
编写上述代码后,flycheck检测到unix.Malloc类型警告:
Attempt to free released memory
需求是在单个循环中实现逐字节的缓冲区内存分配。
问题根因
当前代码存在三个致命的内存逻辑错误:
- 循环里每次调用
malloc都会直接覆盖buffer保存的地址,之前分配的内存地址彻底丢失,直接造成内存泄漏 - 每次只申请1字节内存,写入字符后就执行
++buffer移动指针,后续的写入操作全是在访问未申请的野内存,属于C语言未定义行为,程序运行时随时可能崩溃 - 释放内存时逐字节调用
free的逻辑完全错误:free只能接收malloc/realloc返回的原始内存块首地址,传入移动过的指针本身就是非法操作,还会重复释放不存在的内存块,这就是触发Attempt to free released memory警告的直接原因。
正确实现方案
逐字节扩容缓冲区不需要给每个字符单独调用malloc,用realloc动态调整单块连续内存大小即可,全程在单循环内完成读取,最后统一释放内存:
#include <unistd.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> static void parse_file(char path[11]) { int fd = open(path, O_RDONLY); if (fd == -1) { fprintf(stderr, "Failed to open a file '%s'\n", path); exit(errno); } char c; // 初始分配1字节预留存字符串终止符 char *buffer = malloc(1); if (!buffer) { close(fd); exit(ENOMEM); } unsigned int i = 0; // 单循环完成逐字节读取+内存扩容 while (read(fd, &c, 1) > 0) { // 每次扩容2字节:1字节存当前字符,1字节预留存终止符 char *tmp = realloc(buffer, i + 2); if (!tmp) { free(buffer); close(fd); exit(ENOMEM); } buffer = tmp; buffer[i] = c; i++; buffer[i] = '\0'; // 始终保持字符串合法终止 } close(fd); printf("Buffer data:\n%s\n", buffer); // 缓冲区解析逻辑 // ... // 一次性释放整块连续内存,不需要逐字节操作 free(buffer); }
实现说明
- 全程只维护一块连续堆内存,不存在零散的1字节分配,不会出现内存地址丢失的泄漏问题
- 每读1字节就通过
realloc把内存块扩容对应长度,直接按下标写入字符,不需要移动缓冲区头指针 - 内存块末尾始终预留1字节存储字符串终止符
\0,可直接用标准字符串函数操作 - 最后将
realloc维护的原始首地址传入free,一次调用即可释放全部内存,完全符合C内存管理规范,不会触发非法内存访问、重复释放的警告。
内容的提问来源于stack exchange,提问作者siery
相关产品推荐
相关产品推荐

