代码正常运行但Valgrind检测时因realloc无限循环,求排查解决
问题:逐字符读取文件到动态扩容内存时Valgrind无限运行
我尝试将文件中的字符逐字符复制到一块可随文件大小动态扩容的内存块中,代码能正常输出内容,但用Valgrind检测时会无限运行。我试过用临时指针接收realloc的返回值再赋值给原指针,但问题依旧。
原代码
#include <stdio.h> #include <stdlib.h> #include <ctype.h> int main(void) { FILE *dict = fopen("dictionaries/large", "r"); if (dict == NULL) { printf("Could not load the file\n"); return 1; } // Buffer to read data. char *buffer = malloc(1); if (buffer == NULL) { return 1; } char *word = malloc(1); if (word == NULL) { return 1; } int i = 0; // Load file byte per byte. Copy char per char. while (fread(buffer, 1, 1, dict)) { word[i] = buffer[0]; i++; char *tmp = realloc(word, i + 1); word = tmp; } printf("%s\n", word); fclose(dict); free(buffer); free(word); }
问题根源
- 缺少字符串结束符:
printf("%s")会持续读取内存直到遇到\0,但代码未在word末尾添加该标记,导致越界访问。Valgrind会持续追踪这个非法访问行为,最终出现无限运行的情况。 - 频繁调用realloc:每读取一个字符就调用一次
realloc,不仅效率极低,还会产生大量内存碎片,加重Valgrind的检测负担。 - 不必要的内存分配:
buffer仅用于存储单个字符,完全没必要用malloc,直接用char变量即可。
修复后的代码
#include <stdio.h> #include <stdlib.h> int main(void) { FILE *dict = fopen("dictionaries/large", "r"); if (dict == NULL) { printf("Could not load the file\n"); return 1; } // 初始分配足够容量,避免频繁扩容 size_t capacity = 16; char *word = malloc(capacity); if (word == NULL) { fclose(dict); return 1; } size_t i = 0; char c; // 逐字符读取文件 while (fread(&c, 1, 1, dict)) { // 容量不足时按2倍扩容,平衡内存占用和扩容次数 if (i + 1 >= capacity) { capacity *= 2; char *tmp = realloc(word, capacity); if (tmp == NULL) { free(word); fclose(dict); printf("Memory allocation failed\n"); return 1; } word = tmp; } word[i] = c; i++; } // 必须添加字符串结束符,确保printf和其他字符串函数正常工作 word[i] = '\0'; printf("%s\n", word); fclose(dict); free(word); return 0; }
修复说明
- 移除了多余的
buffer,直接用char变量读取字符,减少内存浪费。 - 采用初始预分配+倍数扩容的策略,大幅降低
realloc调用次数,提升程序效率,同时减轻Valgrind的检测压力。 - 强制在
word末尾添加\0,彻底解决越界访问问题,这也是Valgrind无限运行的核心原因。 - 完善了内存分配失败的错误处理,避免出现内存泄漏。
内容的提问来源于stack exchange,提问作者DumbDumbie
相关产品推荐
相关产品推荐

