我有以下ANSI C代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char *buffer = 0;
int length = 0;
FILE *f = fopen("text.txt", "r");
if(f) {
fseek(f, 0, SEEK_END);
length = ftell(f);
fseek(f, 0, SEEK_SET);
buffer = malloc(length);
fread(buffer, 1, length, f);
fclose (f);
}
printf("File size: %d\nBuffer size: %d\nContent: %s\n=END=", length, strlen(buffer), buffer);
return 0;
}
由于某种原因,在malloc之后需要更多的内存并从内存中输出额外的垃圾,例如: 首先运行:
File size: 12 Buffer size: 22 Content: 123456789012les=$#▬rW| =END=
第二轮:
File size: 12 Buffer size: 22 Content: 123456789012les↔1↕.' =END=
第三次运行:
File size: 12 Buffer size: 22 Content: 123456789012les=▬kπà =END=
有人可以帮我解决这个问题并解释为什么我的版本表现得很奇怪吗? 我使用MingW TDM-GCC 4.9.2 32bit进行编译(gcc)
答案 0 :(得分:4)
你有undefined behavior(this解释为什么你应该害怕UB) - 因为buffer overflow。你忘了添加一个终止空字节。
替换错误的行:
// WRONG CODE:
buffer = malloc(length);
fread(buffer, 1, length, f);
与
buffer = malloc(length+1);
if (!buffer)
{ perror("malloc"); exit(EXIT_FAILURE); };
memset (buffer, 0, length+1);
if (fread(buffer, 1, length, f) < length)
{ perror("fread"); exit(EXIT_FAILURE); };
(你可以将结束字节归零;我更愿意用memset
清除整个缓冲区)
顺便说一下,ANSI C已经过时了。您应该使用符合C11标准的编译器(例如最近 GCC用作gcc -std=c11 -Wall -Wextra -g
)并且目标C11符合性(或至少C99)。学习使用调试器(例如gdb
)
答案 1 :(得分:0)
使用fseek(f, 0, SEEK_END);
会调用未定义的行为。首先,您不是以二进制模式读取,因此文件中的字节数不一定是要读取的字节数。
但是如果你切换到二进制流,则按照C Standard的<7.1}。
二进制流无需支持
fseek
调用whence
的{{1}}值。
和
将文件位置指示器设置为文件结尾,如同
SEEK_END
,对于二进制文件具有未定义的行为 流(因为可能是尾随空字符)或任何 具有状态依赖编码的流,但不能确定地结束 初始转变状态。