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

C语言读取文件到内存报malloc(): corrupted top size错误排查

错误产生原因

这个报错的本质是堆内存越界写入破坏了malloc维护的堆块元数据,你的代码存在多个明确的内存错误,取消注释printf("\n")后能运行纯粹是未定义行为下的巧合,不代表代码本身正确:

  • 最核心的问题是指针类型和申请内存大小不匹配:你用int *dict = malloc(size)申请了size字节的内存,但int类型在绝大多数主流系统上占4字节。C语言的指针偏移是按指向类型的长度计算的,*(dict + i)实际访问的地址是(char*)dict + i * sizeof(int)——也就是每循环一次i,实际向后跳4个字节,循环还没跑完就已经写到申请的内存块范围外,刚好覆盖了glibc malloc在堆块头部存储的长度、前后块链接信息这类元数据,最后执行free时检测到元数据损坏,就抛出malloc(): corrupted top size错误。
  • 第二个问题是循环边界错误:你申请了size字节的内存,合法访问的下标范围是0~size-1,但读文件的循环写的是i <= size,会多写入1个元素,哪怕把指针改成正确的char*类型,这一步也会造成越界写。
  • 至于取消注释printf就正常运行,完全是内存布局变化导致的偶然现象:printf执行时会申请临时的栈/堆空间,改变了进程的内存排布,你越界写入的位置刚好落在printf使用的临时内存区域,没有踩到malloc的关键元数据,所以没有触发报错。但越界问题始终存在,换编译选项、换系统、换不同大小的输入文件,程序随时可能崩溃。
其他隐藏的潜在问题
  • 没有校验命令行参数:运行时如果没传入文件路径,argv[1]为NULL,直接调用fopen会触发空指针访问崩溃。
  • 没有校验文件打开结果:如果指定文件不存在、当前用户没有读权限,fopen会返回NULL,后续的fseek、ftell等调用都会崩溃。
  • 没有处理不可seek的流:如果传入的是管道、终端、字符设备这类不支持随机访问的文件,fseek/ftell会调用失败,ftell返回-1转成无符号数会变成超大值,导致malloc申请异常大的内存、后续读写大面积越界。
  • 读文件时没有判断EOF:如果文件读取中途出错,或者实际可读内容比ftell返回的长度短,会把EOF值(-1)反复写入内存,导致输出乱码。
  • 没有关闭打开的文件句柄,虽然程序退出时系统会自动回收资源,但属于不规范写法。
修复方案

首先把存储文件内容的指针改成char*类型(存储单字节字符不需要用int类型),修正循环边界,补全所有必要的错误校验,参考修复代码如下:

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

int main(int argc, char const *argv[])
{
    // 校验命令行参数
    if (argc < 2) {
        fprintf(stderr, "Usage: %s <file_path>\n", argv[0]);
        return 1;
    }

    FILE *fp = fopen(argv[1], "r");
    // 校验文件打开结果
    if (!fp) {
        perror("Open file failed");
        return 1;
    }

    // 校验seek操作结果
    if (fseek(fp, 0, SEEK_END) != 0) {
        perror("Seek file failed");
        fclose(fp);
        return 1;
    }

    long file_size = ftell(fp);
    // 校验ftell返回值
    if (file_size == -1) {
        perror("Get file size failed");
        fclose(fp);
        return 1;
    }
    rewind(fp);

    char *buf = malloc(file_size);
    if (!buf) {
        perror("Malloc memory failed");
        fclose(fp);
        return 1;
    }

    int c;
    unsigned long read_len = 0;
    // 修正循环边界,同时判断EOF避免读异常
    for (; read_len < file_size && (c = getc(fp)) != EOF; read_len++) {
        buf[read_len] = (char)c;
    }

    // 按实际读到的长度输出
    for (unsigned long i = 0; i < read_len; i++) {
        putchar(buf[i]);
    }

    free(buf);
    fclose(fp);
    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 10:12:20