C中奇怪的malloc行为

时间:2015-09-22 08:51:26

标签: c malloc

我有以下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)

2 个答案:

答案 0 :(得分:4)

你有undefined behaviorthis解释为什么你应该害怕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

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

答案 1 :(得分:0)

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

但是如果你切换到二进制流,则按照C Standard的<7.1}。

  

二进制流无需支持fseek调用   whence的{​​{1}}值。

  

将文件位置指示器设置为文件结尾,如同   SEEK_END,对于二进制文件具有未定义的行为   流(因为可能是尾随空字符)或任何   具有状态依赖编码的流,但不能确定地结束   初始转变状态。