C中奇怪的malloc行为

我有以下ANSI C代码:

#include  #include  #include  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之后需要更多的内存并从内存中输出额外的垃圾,例如:首先运行:

 文件大小:12
缓冲区大小:22
内容:123456789012les = $#▬rW|
 = END = 

第二轮:

 文件大小:12
缓冲区大小:22
内容:123456789012les↔1↕。'
 = END = 

第三轮:

 文件大小:12
缓冲区大小:22
内容:123456789012les =▬kπà
 = END = 

有人可以请帮助我,并解释为什么我的版本表现得很奇怪? 我使用MingW TDM-GCC 4.9.2 32bit进行编译(gcc)

你有未定义的行为 ( 这解释了为什么你应该害怕UB) – 因为缓冲区溢出 。 你忘了添加一个终止空字节。

更换有缺陷的线路:

  // 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 -std=c11 -Wall -Wextra -g GCC )和目标C11符合性(或至少C99 )。 学习使用调试器 (例如gdb

仔细阅读malloc(3) , fread(3) , perror(3)等文档....

使用fseek(f, 0, SEEK_END); 调用未定义的行为。 首先,您不是以二进制模式读取,因此文件中的字节数不一定是要读取的字节数。

但是如果你切换到二进制流,按照C标准的 7.19.9.2:

二进制流不需要有意义地支持具有whence值的fseek调用。

将文件位置指示符设置为文件结尾,与fseek(file, 0, SEEK_END) ,具有二进制流的未定义行为 (因为可能是尾随空字符)或具有不依赖于状态的编码的任何流确定在初始class次状态结束。