已预留'\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
相关产品推荐
相关产品推荐

