Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 当文件末尾没有新行时,fgets无法正确读取_C_File - Fatal编程技术网

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

C 当文件末尾没有新行时,fgets无法正确读取,c,file,C,File,问题是,如果文件末尾没有新行,fgets显示错误。假设我有两个文本文件,如下所示 text1.txt的内容: German Hoy 43 68 Jesse Boster 88 29 German Hoy 43 68 Jesse Boster 88 29 while( fgets (s, 60, file)!=NULL ) { s[strlen(s)-1] = '\0'; strcpy(tempName, s); fgets(s, 60, f

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

text1.txt的内容:

German Hoy
43
68
Jesse Boster
88
29
German Hoy
43
68
Jesse Boster
88
29
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);
    }
  • 请注意,文件在29之后完全结束。29号以后没有电话
text2.txt的内容:

German Hoy
43
68
Jesse Boster
88
29
German Hoy
43
68
Jesse Boster
88
29
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);
    }
  • 请注意,29后面还有一行
我的问题:

German Hoy
43
68
Jesse Boster
88
29
German Hoy
43
68
Jesse Boster
88
29
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);
    }
当文件结尾后还有一行时,程序将正确运行text2.txt。但是,如果我在文件末尾没有像text1.txt这样的一行代码,就不会出现这种情况。我怎样才能解决这个问题?我希望得到相同的结果,不管文件末尾是否还有一行。(在这两种情况下,它应输出相同的结果)

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

German Hoy
43
68
Jesse Boster
88
29
German Hoy
43
68
Jesse Boster
88
29
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

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

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

German Hoy
43
68
Jesse Boster
88
29
German Hoy
43
68
Jesse Boster
88
29
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);
    }

您必须确保您的缓冲区长度至少为61字节,以适合新行。

您可以在
s
缓冲区的末尾添加额外的新行,而不必考虑

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

German Hoy
43
68
Jesse Boster
88
29
German Hoy
43
68
Jesse Boster
88
29
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);
    }

您必须确保缓冲区长度至少为61字节,以适合新行。

可选地剥离新行:

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()

选择性地剥离新行:

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()

此代码大约是一个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;
}
这正是我所期望的,因为您的代码会清除最后一行的最后一个字符,而不管它是否为换行符。如果希望输出包含
29
9
,则必须更加小心:

s[strcspn(s, "\n")] = '\0';
部署3次更改后,两个程序的输出相同


有什么区别
strcspn()。如果没有换行符,它将报告空字节,赋值将用另一个空字节(no-op)覆盖空字节。但它是可靠和安全的。

此代码大约是一个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;
}
这正是我所期望的,因为您的代码会清除最后一行的最后一个字符,而不管它是否为换行符。如果希望输出包含
29
9
,则必须更加小心:

s[strcspn(s, "\n")] = '\0';
部署3次更改后,两个程序的输出相同


有什么区别
strcspn()。如果没有换行符,它会报告空字节,赋值会用另一个空字节覆盖空字节-一个no-op。但是它是可靠和安全的。

您得到了什么输出?您应该检查每个
fgets()
调用,以确保没有收到EOF报告。您应该向我们展示一个MCVE()-例如,您的
setup()
调用可以被合适的
printf()
调用替换。还有,你在哪个平台上工作?Windows与类Unix可能会有所不同。
s[strlen(s)-1]='\0'替换为
s[strcspn(s,“\n”)]='\0'。第二个和第三个
s[strlen(s)-1]='\0'是不必要的。感谢您的更新-除了更新不是MCVE,输入与前面描述的完全不同,并且您得到的输出丢失,并且您期望的输出从您显示的输入中不明显。事实上,更新一点帮助都没有。你得到了什么结果?您应该检查每个
fgets()
调用,以确保没有收到EOF报告。您应该向我们展示一个MCVE()-例如,您的
setup()
调用可以被合适的
printf()
调用替换。还有,你在哪个平台上工作?Windows与类Unix可能会有所不同。
s[strlen(s)-1]='\0'替换为
s[strcspn(s,“\n”)]='\0'。第二个和第三个
s[strlen(s)-1]='\0'是不必要的。感谢您的更新-除了更新不是MCVE,输入与前面描述的完全不同,并且您得到的输出丢失,并且您期望的输出从您显示的输入中不明显。事实上,这个更新一点帮助都没有。末尾已经有一个空字节;你只添加了一个字符,所以缓冲区中只需要61个字节。你是对的,我认为fgets将执行类似于strcpy的操作:)@ameen是的,现在已修复,非常感谢!为什么不省略3行
length=strlen(s);s[length]='\n';s[length+1]='\0'?因为问题是当文件末尾没有换行符时,末尾已经有一个空字节;你只需要加一个c