当文件末尾没有新行时,fgets无法正确读取

时间:2017-03-04 21:29:36

标签: c file

问题是如果文件末尾没有新行,则fgets显示错误。假设我有2个文本文件,如下,

text1.txt的内容:

German Hoy
43
68
Jesse Boster
88
29
  • 请注意,文件在29之后完全结束.29之后没有行。

text2.txt的内容:

German Hoy
43
68
Jesse Boster
88
29
  • 请注意,29之后还有一行。

我的问题:

当文件结束后还有一行时,程序对text2.txt运行正确。但是,如果我在文件的末尾没有一行,如text1.txt,则不会这样做。我怎样才能解决这个问题?我希望得到相同的结果,无论是否在文件的末尾有一行。 (在这两种情况下,它应该输出相同的结果)

以下是与问题相关的源代码的一部分:

while( fgets (s, 60, file)!=NULL )  {
        s[strlen(s)-1] = '\0';
        strcpy(tempName, s);

        fgets(s, 60, file);
        s[strlen(s)-1] = '\0';
        sscanf(s, "%d", &tempMid);

        fgets(s, 60, file);
        s[strlen(s)-1] = '\0';
        sscanf(s, "%d", &tempFinal);

        setup(tempName, tempMid, tempFinal);
    }

使用的系统是LINUX

3 个答案:

答案 0 :(得分:3)

可选择剥离新行:

while( fgets (s, 60, file)!=NULL )  {
  s[strcspn(s, "\n")] = '\0';

不要使用s[strlen(s)-1] = '\0';,因为它可能是黑客攻击。 fgets()读取空字符,就像任何其他非新行字符一样。行中的第一个字符可能是'\0',然后OP的代码调用未定义的行为。

此外,在OP代码中,甚至不需要删除潜在的新行字符。

    fgets(s, 60, file);
    // s[strlen(s)-1] = '\0';
    sscanf(s, "%d", &tempMid);

最好测试sccanf()的返回值或使用strtol()

答案 1 :(得分:2)

您可以在s缓冲区末尾添加额外的新行,无论

fgets(s, 60, file);
length = strlen(s);
s[length] = '\n';
s[length+1] = '\0';
sscanf(s, "%d", &tempFinal);

重要提示:

您必须确保缓冲区长度至少为61个字符以适应新行。

答案 2 :(得分:1)

此代码大约是MCVE:

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

int main(void)
{
    char s[60];
    char tempName[60];
    int tempMid;
    int tempFinal;
    FILE *file = stdin;

    while (fgets(s, 60, file) != NULL)
    {
        s[strlen(s) - 1] = '\0';
        strcpy(tempName, s);

        if (fgets(s, 60, file) == NULL)
            break;
        s[strlen(s) - 1] = '\0';
        sscanf(s, "%d", &tempMid);

        if (fgets(s, 60, file) == NULL)
            break;
        s[strlen(s) - 1] = '\0';
        sscanf(s, "%d", &tempFinal);

        printf("[%s] %d %d\n", tempName, tempMid, tempFinal);
    }

    return 0;
}

它会将您编写的片段包含在main()中,并带有两个标头,使其适应标准输入读取,并检查fgets()调用是否都成功。

我打电话给程序fg17。当你在两个数据文件上运行时,我得到:

$ fg17 < text1.txt
[German Hoy] 43 68
[Jesse Boster] 88 2
$ fg17 <text2.txt
[German Hoy] 43 68
[Jesse Boster] 88 29
$

这是我的预期,因为你的代码会删除最后一行的最后一个字符,无论它是否是换行符。如果您希望输出包含9 29,那么您必须更加小心:

s[strcspn(s, "\n")] = '\0';

如果部署了3次更改,则两个程序的输出相同。

有什么区别? strcspn()返回字符串参数中未找到的字符数 - 或返回空字节的字符数。如果没有换行符,则报告空字节,并且赋值用另一个空字节覆盖空字节 - 无操作。但它是可靠和安全的。