代码之家  ›  专栏  ›  技术社区  ›  GEOCHET S.Lott

为什么我的简单C程序向标准输出显示垃圾?

  •  9
  • GEOCHET S.Lott  · 技术社区  · 17 年前

    考虑以下简单的C程序,该程序将文件读入缓冲区并将该缓冲区显示到控制台:

    #include<stdio.h>
    
    main()
    {
      FILE *file;
        char *buffer;
        unsigned long fileLen;
        //Open file
        file = fopen("HelloWorld.txt", "rb");
        if (!file)
        {
            fprintf(stderr, "Unable to open file %s", "HelloWorld.txt");
            return;
        }
        //Get file length
        fseek(file, 0, SEEK_END);
        fileLen=ftell(file);
        fseek(file, 0, SEEK_SET);
        //Allocate memory
        buffer=(char *)malloc(fileLen+1);
        if (!buffer)
        {
            fprintf(stderr, "Memory error!");
            fclose(file);
            return;
        }
        //Read file contents into buffer
        fread(buffer, fileLen, 1, file);
        //Send buffer contents to stdout
        printf("%s\n",buffer);    
        fclose(file);
    }
    

    它将读取的文件仅包含:

    输出为:

    我已经有一段时间没有在C/C++中做任何重要的事情了,但通常我会假设缓冲区的分配比需要的大,但情况似乎并非如此。

    fileLen最终是12岁,这是准确的。

    我现在想我一定是显示缓冲区出错了,但我不确定我做错了什么。

    5 回复  |  直到 16 年前
        1
  •  40
  •   JesperE    17 年前

    您需要NUL终止您的字符串。添加

    buffer[fileLen] = 0;
    

    在打印之前。

        2
  •  28
  •   George Eadon    17 年前

    JesperE的方法会起作用,但您可能有兴趣知道有另一种处理方法。

    printf 作为字符串字段的精度:

    printf("%.*s\n", fileLen, buffer);
    

        3
  •  8
  •   Robert Gamble    17 年前

    JesperE在您的示例中关于nul终止问题是正确的,我只想补充一点,如果您正在处理文本文件,最好使用fgets()或类似的工具,因为这将正确处理跨不同平台的换行符序列,并且将始终为您nul终止字符串。如果您真正使用的是二进制数据,则不希望使用printf()输出数据,因为printf函数需要字符串,数据中的nul字节将导致输出截断。

        4
  •  3
  •   Alok Singhal    16 年前

    您确定文件大小的方法是查找文件的末尾,然后使用 ftell()

    • 如果是文本文件,则打开时不带 "b" fopen() 那就打电话吧 ftell() 可能不会告诉您可以从文件中读取的字符数。例如,windows使用两个字节作为行尾,但在读取时,它是一个字节 char ftell() fseek() ,而不是确定文件大小。
    • 如果是二进制文件,则使用 “b” 在第二个参数中

      将文件位置指示器设置为文件结尾,如 fseek(file, 0, SEEK_END) ,具有二进制流的未定义行为(因为可能的尾随空字符),或具有状态相关编码的任何流的未定义行为,这些编码不一定以初始移位状态结束。

    fread() 要阅读,如果您碰巧需要更多内存,请使用 realloc() mmap() ,或者可以保证将二进制流的文件位置指示器设置为文件结尾,但依赖这些指示器是不可移植的。

    另请参见此C-FAQ: What's the difference between text and binary I/O? .

        5
  •  0
  •   dreamlax    16 年前

    你可以用 calloc 而不是 malloc 分配已初始化的内存。 分配 指示数组中要为其分配内存的元素数,第二个参数是每个元素的大小。因为一个 char 总是1,我们可以通过 1

     buffer = calloc (fileLen + 1, 1);
    

    马洛克 或 分配 分配 马洛克 因为在给你之前,它必须把你要求的所有记忆归零。