fgets 无法读取换行符
fgets cannot read newline character
char c[500];
fgets(c, 500, fp);
if (c == "\n") {
customer.checkoutTime = 0;
customer.payment = 0;
}
如果 fgets 读取一个空行,我想在这两个 var 中存储两个零。但是它失败了,从不执行 if-block 代码。 fgets 应该如何读取空行?
c
不是单个字符;它是指向字符序列的指针。您的 if
是在询问这是否与您预先填充换行符的位置相同,如果这样描述,显然永远不会成功。
如果要查看c
指向的第一个字符是否为换行符,请使用if ( *c == '\n' )
。
好的,有几件事:
1。函数行为
来自 description of fgets
函数:
The C library function char *fgets(char *str, int n, FILE *stream)
reads a line from the specified stream and stores it into the string pointed to by str. It stops when either (n-1) characters are read, the newline character is read, or the end-of-file is reached, whichever comes first.
同man fgets
:
fgets() reads in at most one less than size characters from stream and stores them into the buffer pointed to by s. Reading stops after an EOF or a newline. If a newline is read, it is stored into the buffer. A terminating null byte ('[=48=]') is stored after the last character in the buffer.
这是什么意思:
fgets
在遇到 \n
(换行)字符后停止 阅读。但是让我们看看我们可以用结果字符串做什么:
鉴于 fgets
在最多读取 N-1 个字符后停止,您知道,如果 strlen(c)
是 499,则很可能没有遇到 EOF/EOL 个字符。
如果 fgets
遇到 EOL,它会 return 一个 NULL
指针,所以你可以使用它。除此之外,以下是查找新行的方法:
鉴于 c
是一个数组,我还会避免在声明和 fgets
调用中对缓冲区的大小进行硬编码。相反,我会使用:
char c[500], // perhaps a macro here?
*check;
//more code
check = fgets(c, sizeof c, fp); // fgets returns relevant stuff
if (check == NULL || *check == '[=10=]')
//Nothing was read (EOL), or an error occurred,
//or fgets read a nul-character at the start of the line
if (strlen(c) == (sizeof c) -1)
//likely no EOL
else
c[strlen(c) - 1] most likely to be EOL
我添加了 *check == '[=26=]'
检查以响应 chux 的评论之一,以防 fgets
实际上是从文件中读取空字符。由于您只对以 \n
开头的行感兴趣,您只需跳过像这些
这样的行
2。代码问题
除此之外,您发布的代码:
if (c == "\n") {
在几个层面上是错误的。 "\n"
生成一个指向只读字符串 (char *
) 的指针,它永远不会等于 c
。使用 strcmp
比较字符串。对于字符,使用单引号,并比较 c
中的值,您必须取消引用它:
if (c[i] == '\n') // or *c == '\n'
在对 Scott Hunter 的回答的评论中,您提到您 正在 使用 *c == '\n'
检查,这很好,但是 c
在该表达式中衰减为指向数组中第一个元素的指针(即 fgets
读取的第一个字符)。该字符不太可能是新行。
本质上,您正在写 c[0] == '\n'
而您应该查看最后一个字符 (c[strlen(c) - 1] == '\n'
) 以查看您读取的字符串是否以新行结尾
3。 Windows 行尾:
大多数系统使用 \n
作为新行。 Windows 使用 \r\n
。 fgets
实际上会选择 \n
字符,但缓冲区不会为空。 c
的值实际上是:
c[500] = {'\r', '\n', 0};
因此字符串中的第一个字符将不匹配 \n
。您没有指定编码和您使用的系统(也没有指定编译器),但请确保您 trim 任何前导回车符 return 如果需要的话。
这里有更多详细信息 here
这 可能 意味着从代码的角度来看,您看到的空行将不会以 \n
开头,而是以 \r
开头.尝试检查一下:
if (*c == '\r' && c[1] == '\n')
//empty windows line
else if (*c == '\n')
//empty *nix line
else
//line was not empty
char c[500];
fgets(c, 500, fp);
if (c == "\n") {
customer.checkoutTime = 0;
customer.payment = 0;
}
如果 fgets 读取一个空行,我想在这两个 var 中存储两个零。但是它失败了,从不执行 if-block 代码。 fgets 应该如何读取空行?
c
不是单个字符;它是指向字符序列的指针。您的 if
是在询问这是否与您预先填充换行符的位置相同,如果这样描述,显然永远不会成功。
如果要查看c
指向的第一个字符是否为换行符,请使用if ( *c == '\n' )
。
好的,有几件事:
1。函数行为
来自 description of fgets
函数:
The C library function
char *fgets(char *str, int n, FILE *stream)
reads a line from the specified stream and stores it into the string pointed to by str. It stops when either (n-1) characters are read, the newline character is read, or the end-of-file is reached, whichever comes first.
同man fgets
:
fgets() reads in at most one less than size characters from stream and stores them into the buffer pointed to by s. Reading stops after an EOF or a newline. If a newline is read, it is stored into the buffer. A terminating null byte ('[=48=]') is stored after the last character in the buffer.
这是什么意思:
fgets
在遇到 \n
(换行)字符后停止 阅读。但是让我们看看我们可以用结果字符串做什么:
鉴于 fgets
在最多读取 N-1 个字符后停止,您知道,如果 strlen(c)
是 499,则很可能没有遇到 EOF/EOL 个字符。
如果 fgets
遇到 EOL,它会 return 一个 NULL
指针,所以你可以使用它。除此之外,以下是查找新行的方法:
鉴于 c
是一个数组,我还会避免在声明和 fgets
调用中对缓冲区的大小进行硬编码。相反,我会使用:
char c[500], // perhaps a macro here?
*check;
//more code
check = fgets(c, sizeof c, fp); // fgets returns relevant stuff
if (check == NULL || *check == '[=10=]')
//Nothing was read (EOL), or an error occurred,
//or fgets read a nul-character at the start of the line
if (strlen(c) == (sizeof c) -1)
//likely no EOL
else
c[strlen(c) - 1] most likely to be EOL
我添加了 *check == '[=26=]'
检查以响应 chux 的评论之一,以防 fgets
实际上是从文件中读取空字符。由于您只对以 \n
开头的行感兴趣,您只需跳过像这些
2。代码问题
除此之外,您发布的代码:
if (c == "\n") {
在几个层面上是错误的。 "\n"
生成一个指向只读字符串 (char *
) 的指针,它永远不会等于 c
。使用 strcmp
比较字符串。对于字符,使用单引号,并比较 c
中的值,您必须取消引用它:
if (c[i] == '\n') // or *c == '\n'
在对 Scott Hunter 的回答的评论中,您提到您 正在 使用 *c == '\n'
检查,这很好,但是 c
在该表达式中衰减为指向数组中第一个元素的指针(即 fgets
读取的第一个字符)。该字符不太可能是新行。
本质上,您正在写 c[0] == '\n'
而您应该查看最后一个字符 (c[strlen(c) - 1] == '\n'
) 以查看您读取的字符串是否以新行结尾
3。 Windows 行尾:
大多数系统使用 \n
作为新行。 Windows 使用 \r\n
。 fgets
实际上会选择 \n
字符,但缓冲区不会为空。 c
的值实际上是:
c[500] = {'\r', '\n', 0};
因此字符串中的第一个字符将不匹配 \n
。您没有指定编码和您使用的系统(也没有指定编译器),但请确保您 trim 任何前导回车符 return 如果需要的话。
这里有更多详细信息 here
这 可能 意味着从代码的角度来看,您看到的空行将不会以 \n
开头,而是以 \r
开头.尝试检查一下:
if (*c == '\r' && c[1] == '\n')
//empty windows line
else if (*c == '\n')
//empty *nix line
else
//line was not empty