由fgets回车

时间:2012-10-07 13:32:38

标签: c string fgets carriage-return

我正在运行以下代码:

#include<stdio.h>
#include<string.h>
#include<io.h>

int main(){
    FILE *fp;
    if((fp=fopen("test.txt","r"))==NULL){
        printf("File can't be read\n");
        exit(1);
    }
    char str[50];
    fgets(str,50,fp);
    printf("%s",str);
    return 0;
}

text.txt包含:I am a boy\r\n

由于我在Windows上,它需要\ r \ n作为新行字符,所以如果我从文件中读取它,它应该"I am a boy\n\0"存储str,但我得到{{1 }}。我正在使用mingw编译器。

3 个答案:

答案 0 :(得分:7)

行为取决于c库实现以及传递给fopen的模式。请参阅fopen (fopen on MSDN)上的MSDN文档中的此引用:

  

b - 以二进制(未翻译)模式打开;涉及回车符和换行符的翻译被抑制。

意味着,如果您使用Microsoft c库,并打开省略'b'的文件,则将从流中删除回车符。

由于你正在使用mingw,你的编译器可能会链接到遵循POSIX标准的GNU c库。这就是GNU文档中关于fopen (fopen on gnu.org)

的内容
  

opentype中的字符'b'具有标准含义;它请求二进制流而不是文本流。但这对POSIX系统(包括GNU系统)没有任何影响。

结论:你省略了'b'模式char,它以文本模式打开你的流。你在Windows上,但使用GNU c库,它在文本和二进制模式之间没有区别。这就是fgets同时读取回车符和新行的原因。

答案 1 :(得分:5)

  

由于我在Windows上,它需要\ r \ n作为换行符...

这个假设是错误的。 C标准将回车和新线视为两种不同的东西,如C99§5.2.1/ 3(字符集)所示:

  

[...]在基本执行字符集中,应该有   控制表示警报,退格,回车和换行的字符。 [...]

fgets函数描述如下,在C99§7.19.7.2/ 2中:

  

fgets函数最多读取一个小于n指定的字符数   从流指向的流进入s指向的数组。 没有额外的   在新行字符(保留)之后或文件结束后读取字符。一个   在读入数组的最后一个字符后立即写入空字符。

因此,遇到字符串I am a boy\r\n时,符合要求的实现应该读取\n字符。实施应基于平台放弃\r,这是不可能的理由。

答案 2 :(得分:1)

c 标准对中的文本流(以及其他内容)是这样说的:

<块引用>

可能需要在输入和输出时添加、更改或删除字符以 符合在宿主中表示文本的不同约定 环境。因此,之间不需要一一对应 流中的字符和外部表示中的字符。数据读入 来自文本流的数据必然等于 仅在以下情况下才较早地写入该流: 数据仅包含打印 字符和控制字符水平制表符和换行符;没有换行 字符紧跟在空格字符之前;和最后一个字符 是换行符。

换句话说,如果一个文件在文本模式下打开,一个实现可以自由地添加、删除和修改控制字符,如果它想要/需要在往返磁盘时。这显然是 microsoft 实现对回车所做的,但 gnu 实现没有。