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

使用read和realloc读取未知大小文件时报realloc无效指针错误

错误原因分析

第一次报错 realloc(): invalid pointer

realloc要求传入的指针必须是malloc/calloc/realloc返回的堆内存起始地址,你最初的实现里每次读完都执行buf += curr_read_size,把起始指针偏移了,传入偏移后的指针不符合realloc的调用要求,直接触发错误。

第二次报错 realloc(): invalid next size

修改后的代码存在两个核心问题,直接导致堆内存越界、破坏了堆的管理元数据:

  1. 读操作越界:每次调用read时第三个参数直接传了整个缓冲区的大小buf_size,但此时缓冲区里已经存了tot_read字节的内容,剩余可用空间只有buf_size - tot_read,你让read读超过剩余空间的长度,就会往缓冲区外写数据,破坏堆结构。
  2. 扩容判断逻辑错误:你用curr_read_size >= buf_size作为扩容条件完全不对,curr_read_size是本次实际读到的字节数,等你读到的数据已经触发这个条件时,越界写入已经发生,堆结构早就被破坏了。

正确实现方案

核心逻辑是:每次读之前先检查剩余可用空间,不够就先扩容,再把数据读到缓冲区的末尾,全程不修改原始堆指针的起始地址。
这里给出修复后的代码,同时增加了输出参数返回读取到的总字节数,避免调用者不知道缓冲区有效内容长度:

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

// 参数size_out用于输出读取到的总字节数,不需要可以删掉
unsigned char* read_unknown_size(int fd, size_t* size_out){
    size_t buf_size = 1024; // 建议用2的幂次作为初始大小,内存分配效率更高
    size_t tot_read = 0;
    ssize_t curr_read_size; // read返回值是ssize_t,不要强转成int避免溢出
    unsigned char* buf = malloc(buf_size);
    if(!buf){
        perror("malloc failed");
        exit(EXIT_FAILURE);
    }

    while(1){
        // 先算剩余可用空间,小于1/2总大小就先扩容,避免频繁调用realloc
        if(buf_size - tot_read < buf_size / 2){
            size_t new_size = buf_size * 2;
            unsigned char* tmp = realloc(buf, new_size);
            if(!tmp){
                perror("realloc failed");
                free(buf); // 出现错误先释放已分配的内存,避免内存泄漏
                exit(EXIT_FAILURE);
            }
            buf = tmp;
            buf_size = new_size;
        }
        // 只读剩余可用空间的长度,不会越界
        curr_read_size = read(fd, buf + tot_read, buf_size - tot_read);
        if(curr_read_size == -1){
            perror("read failed");
            free(buf);
            exit(EXIT_FAILURE);
        }
        if(curr_read_size == 0){
            break; // 读到文件末尾退出
        }
        tot_read += curr_read_size;
    }
    // 如果是读文本内容,可以加下面这行给末尾加结束符,读二进制可以删掉
    // buf[tot_read] = '\0';

    if(size_out != NULL){
        *size_out = tot_read;
    }
    return buf;
}

额外注意点

  • 调用完这个函数后,不要忘记手动free返回的缓冲区,避免内存泄漏。
  • 不要提前保存初始的buf地址作为返回值,realloc可能会把整块内存迁移到新的地址,直接返回扩容后的buf即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 04:24:00