为何fread()读取文件时返回额外垃圾值?
问题分析与解决方案
首先明确:你必须添加空终止符,原因是printf("%s")会持续输出直到遇到\0空字符,但通过fread读取的文件内容本身不包含这个终止符,而malloc分配的内存末尾是未初始化的随机值,这就是你看到垃圾值的原因。换行符越多垃圾值越多,是因为文本模式下文件的换行符转换(比如Windows下\n会被转为\r\n)导致计算的length和实际读取的字节数有偏差,进一步加剧了越界读取的问题。
具体修改方案(除calloc外)
方案1:分配内存时多留1字节,手动添加空终止符
修改你的代码,主要调整内存分配和添加终止符的步骤,同时补充必要的错误检查:
#define _CRT_SECURE_NO_DEPRECATE #include <stdio.h> #include <stdlib.h> int main() { long length; char* content; FILE *file = fopen("text.txt", "rb"); // 用二进制模式打开,避免文本模式的换行转换问题 if (file == NULL) { // 检查文件是否成功打开 perror("Failed to open file"); return 1; } fseek(file, 0, SEEK_END); length = ftell(file); if (length == -1) { // 检查ftell是否成功 perror("Failed to get file length"); fclose(file); return 1; } fseek(file, 0, SEEK_SET); content = (char *)malloc(length + 1); // 多分配1字节用于存储空终止符 if (content == NULL) { // 检查内存分配是否成功 perror("Failed to allocate memory"); fclose(file); return 1; } size_t read_bytes = fread(content, 1, length, file); if (read_bytes != length) { // 检查实际读取的字节数是否符合预期 fprintf(stderr, "Only read %zu bytes out of %ld\n", read_bytes, length); } content[read_bytes] = '\0'; // 用实际读取的字节数来设置终止符,更严谨 printf("%s\n", content); free(content); // 记得释放内存 fclose(file); // 关闭文件 return 0; }
关键修改点说明
- 用
"rb"二进制模式打开文件:避免Windows系统中文本模式下的换行符转换(\n转为\r\n),确保ftell获取的长度和实际文件字节数一致。 - 分配
length + 1字节的内存:预留空终止符的位置。 - 添加
content[read_bytes] = '\0';:用实际读取的字节数而非length来设置终止符,因为fread可能因为文件问题读取的字节数少于预期,这样更安全。 - 补充错误检查:避免文件打开失败、内存分配失败等异常情况导致程序崩溃。
方案2:读取后直接在内存末尾覆盖(不推荐)
如果不想多分配内存,也可以在读取后将content的第length位设为\0,但这个操作存在风险——malloc分配的内存块后面的空间不属于程序,强行写入可能触发内存错误,因此仅在确认内存有额外可写空间时使用,优先推荐方案1。
内容的提问来源于stack exchange,提问作者shashankssc02
相关产品推荐
相关产品推荐

