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

已预留'\0'空间仍触发0 bytes after block of size 7 alloc'd错误的原因?

解决Valgrind报"0 bytes after a block of size 7 alloc'd"的内存越界问题

咱们一步步拆解你的问题,核心是内存分配的大小和你实际使用的空间完全不匹配,导致写入越界触发Valgrind错误。下面是具体分析和修复方案:

问题根源

  • 扩容逻辑完全脱节:你初始分配7字节,把size设为5(意思是最多存5个字符?),但当i == size时,居然还是realloc成7字节,然后把size加到10?这就相当于告诉程序"现在可以存10个字符了",但实际只给了7字节空间,当i增长到6、7...的时候,必然会写到分配的内存块外面,直接触发越界错误。
  • 空终止符的预留逻辑没落地:你说预留了'\0'的空间,但实际分配的7字节最多只能存6个字符+1个'\0',但你的size设为5,当i涨到6的时候,已经把7字节全占了,这时候要么没法加'\0',要么写入字符就越界。
  • fclose的致命错误:在fopen失败的分支里,你居然对NULL的fp调用fclose,这会导致未定义行为,轻则程序崩溃,重则出现奇怪的内存错误。

修复后的代码

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

// 假设这是你的put函数,保留占位
void put(const char* token) {
    printf("Parsed token: %s\n", token);
}

void parse_file(char file[]) { 
    char read = 0; 
    // size表示当前能容纳的最大有效字符数,+1是给'\0'留位置
    int size = 5; 
    char *token = malloc((size + 1) * sizeof(char)); 
    int i = 0; 
    FILE *fp = fopen(file, "r"); 

    if(fp == NULL) { 
        fprintf(stderr, "%s: No such file or directory\n", file); 
        free(token); 
        // fp为NULL时绝对不能调用fclose
        return; 
    } 

    read = fgetc(fp); 
    while(read != EOF) { 
        // 当i等于size时,说明当前空间已经用完,需要扩容
        if(i == size) { 
            size += 5; // 每次增加5个字符的容量
            char *temp = realloc(token, (size + 1) * sizeof(char));
            // 务必检查realloc是否失败,避免内存泄漏或崩溃
            if(temp == NULL) {
                fprintf(stderr, "Memory allocation failed\n");
                free(token);
                fclose(fp);
                return;
            }
            token = temp;
        } 

        if(isalpha(read)) { 
            read = (char) tolower(read); 
            token[i] = read; 
            i++; 
        } else { 
            // 只有当token里有有效字符时才处理
            if(i > 0) { 
                token[i] = '\0'; 
                put(token); 
            } 
            // 重置token,重新分配初始容量
            free(token);
            size = 5;
            token = malloc((size + 1) * sizeof(char)); 
            i = 0; 
        } 
        read = fgetc(fp); 
    } 

    // 处理文件末尾可能残留的未输出token
    if(i > 0) {
        token[i] = '\0';
        put(token);
    }

    free(token); 
    fclose(fp); 
}

关键修改说明

  • 内存分配对齐:所有malloc/realloc都用(size + 1) * sizeof(char),size是有效字符数,+1专门给'\0'留位置,彻底避免越界。
  • 扩容逻辑匹配:先把size增加5,再根据新的size分配内存,确保扩容后的空间能容纳新的字符数+终止符。
  • 空终止符正确添加:遇到非字母时,只在有有效字符的情况下添加'\0',同时处理文件末尾的残留token,避免遗漏。
  • 修复fclose错误:去掉对NULL指针的fclose调用,同时增加realloc失败的检查,让程序更健壮。
  • 移除冗余calloc:用malloc替代calloc,因为我们不需要初始化内存,节省不必要的开销。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:50:44