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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 07:36:31