C 使用feof()从文件读取并退出循环

C 使用feof()从文件读取并退出循环,c,file-io,fgets,feof,C,File Io,Fgets,Feof,说明为什么将feof()用作循环的退出指示器是件坏事 不安全==>在while中有一个feof()签入,在while中有一个fgets() 安全==>拥有fgets()=空检入while本身 我应该看到不安全的代码执行额外的while循环迭代,但两者执行相同(并且正确)的循环数。有人能帮我理解这里发生了什么吗 编辑:这个链接确实说明了为什么会发生这种情况,但我需要在下面找到正确的答案才能准确地理解我所读的内容。我的文件在最后一行没有“\n”,因此得到了相同的结果 以下是文件内容: abcd ef

说明为什么将
feof()
用作循环的退出指示器是件坏事

不安全==>在while中有一个
feof()
签入,在while中有一个
fgets()

安全==>拥有
fgets()=空
检入while本身

我应该看到不安全的代码执行额外的while循环迭代,但两者执行相同(并且正确)的循环数。有人能帮我理解这里发生了什么吗

编辑:这个链接确实说明了为什么会发生这种情况,但我需要在下面找到正确的答案才能准确地理解我所读的内容。我的文件在最后一行没有“\n”,因此得到了相同的结果

以下是文件内容:

abcd
efgh
ijkl
下面是代码:

void testUnsafe(void) {
    FILE *f;
    char buf[20];
    f = fopen("fil.txt", "r");
    while (!feof(f)) {
        fgets(buf, 20, f);
        if (buf[strlen(buf) - 1] == '\n') //cleaner
            buf[strlen(buf) - 1] = '\0';
        printf("%s , %d\n", buf, strlen(buf));
    }
    fclose(f);
}

void testSafe(void) {
    FILE *f;
    char buf[20];
    f = fopen("fil.txt", "r");
    while (fgets(buf, 20, f) != NULL) {
        if (buf[strlen(buf) - 1] == '\n') //cleaner
            buf[strlen(buf) - 1] = '\0';
        printf("%s , %d\n", buf, strlen(buf));
    }
    fclose(f);
}
输出为:

******unsafe test********
abcd , 4
efgh , 4
ijkl , 4
********safe test********
abcd , 4
efgh , 4
ijkl , 4

我尝试了你的两个例子,得到了与你不同的结果。函数
testUnsafe()
将文件的最后一行打印了两次。这有两个原因

  • 如果读取操作试图读取超过文件结尾的内容,则
    feof()
    函数将返回一个非零值

  • 函数
    testUnsafe()

  • 我把你的函数复制到我的测试程序中

    #include <stdio.h>
    #include <string.h>
    
    void testUnsafe(void) {
        FILE *f;
        char buf[20];
        f = fopen("fil.txt", "r");
        while (!feof(f)) {
            fgets(buf, 20, f);
            if (buf[strlen(buf) - 1] == '\n') //cleaner
                buf[strlen(buf) - 1] = '\0';
            printf("%s , %d\n", buf, strlen(buf));
        }
        fclose(f);
    }
    
    void testSafe(void) {
        FILE *f;
        char buf[20];
        f = fopen("fil.txt", "r");
        while (fgets(buf, 20, f) != NULL) {
            if (buf[strlen(buf) - 1] == '\n') //cleaner
                buf[strlen(buf) - 1] = '\0';
            printf("%s , %d\n", buf, strlen(buf));
        }
        fclose(f);
    }
    
    int main()
    {
        testUnsafe();
        printf ("\n\n");
        testSafe();
        return 0;
    }
    
    testUnsafe()
    的输出:

    testSafe()
    的输出:


    我尝试了你的两个例子,得到了与你不同的结果。函数
    testUnsafe()
    将文件的最后一行打印了两次。这有两个原因

  • 如果读取操作试图读取超过文件结尾的内容,则
    feof()
    函数将返回一个非零值

  • 函数
    testUnsafe()

  • 我把你的函数复制到我的测试程序中

    #include <stdio.h>
    #include <string.h>
    
    void testUnsafe(void) {
        FILE *f;
        char buf[20];
        f = fopen("fil.txt", "r");
        while (!feof(f)) {
            fgets(buf, 20, f);
            if (buf[strlen(buf) - 1] == '\n') //cleaner
                buf[strlen(buf) - 1] = '\0';
            printf("%s , %d\n", buf, strlen(buf));
        }
        fclose(f);
    }
    
    void testSafe(void) {
        FILE *f;
        char buf[20];
        f = fopen("fil.txt", "r");
        while (fgets(buf, 20, f) != NULL) {
            if (buf[strlen(buf) - 1] == '\n') //cleaner
                buf[strlen(buf) - 1] = '\0';
            printf("%s , %d\n", buf, strlen(buf));
        }
        fclose(f);
    }
    
    int main()
    {
        testUnsafe();
        printf ("\n\n");
        testSafe();
        return 0;
    }
    
    testUnsafe()
    的输出:

    testSafe()
    的输出:

    如果文本文件在最后一行文本后没有换行符,则
    testUnsafe()
    函数在读取最后一行文本时将到达文件末尾,并生成所显示的三行输出

    如果文本文件在最后一行文本后有换行符,则函数将读取最后一行,包括换行符,而不会到达文件末尾。当它再次进入
    while()
    循环时,它读取零个字符,设置文件结束标志,并输出上一轮仍在缓冲区中的最后一行

    while(!feof(f))
    构造本身并不不安全。它忽略了检查不安全的
    fgets()
    的返回值。

    如果文本文件在最后一行文本后没有换行结束,那么
    testUnsafe()
    函数在读取最后一行时将到达文件末尾,并生成您显示的三行输出

    如果文本文件在最后一行文本后有换行符,则函数将读取最后一行,包括换行符,而不会到达文件末尾。当它再次进入
    while()
    循环时,它读取零个字符,设置文件结束标志,并输出上一轮仍在缓冲区中的最后一行


    while(!feof(f))
    构造本身并不不安全。它忽略了检查不安全的
    fgets()
    的返回值。

    基本上,要读取所有行,必须像那样使用algo。 如果文件末尾没有换行符,则确保加载所有行

    这里的例外是最后一行不确定末尾是否有LF

    除了检查缓冲区溢出等优化内存使用的方法外,您还可以在将缓冲区添加到数组中之前调用realloc()来修剪缓冲区

    buffer = (char*)malloc(bufferSize);
    while(fgets(buffer, bufferSize, file) != NULL) {
        //here store your pointer in array...
        buffer = (char*)malloc(bufferSize);
    };
    free(buffer);
    

    基本上,要阅读所有的行,你必须像那样使用algo。 如果文件末尾没有换行符,则确保加载所有行

    这里的例外是最后一行不确定末尾是否有LF

    除了检查缓冲区溢出等优化内存使用的方法外,您还可以在将缓冲区添加到数组中之前调用realloc()来修剪缓冲区

    buffer = (char*)malloc(bufferSize);
    while(fgets(buffer, bufferSize, file) != NULL) {
        //here store your pointer in array...
        buffer = (char*)malloc(bufferSize);
    };
    free(buffer);
    

    尝试将文件放在netwrok驱动器上,在循环中进行某种暂停,并在读取文件时断开网线。抱歉,正如您所看到的,我不太擅长C语言来理解这里的问题,如果,也就是说,这不是一开始的讽刺。尝试将文件放在netwrok驱动器上,在循环中进行某种暂停,并在读取文件时断开网络电缆。抱歉,正如您所看到的,我不太擅长C来理解这里的问题,如果,也就是说,这不是一开始的讽刺。在@NisseEngström注释之后,这就是它不安全的原因。在最后一行之后没有
    换行符
    ,打印了正确的3行。在选定的情况下(嵌入空字符),
    strlen(buf)
    为0,因此
    if(buf[strlen(buf)-1]
    为UB。@chux:你能给我一个链接,让我可以(轻松地)了解嵌入的空字符吗?我的谷歌搜索结果对我来说有点太难了。@chux的意思是一行,比如
    “\0一些文本\n”
    其中
    fgets()
    将读取并包括
    换行符
    ,但读取后,字符串函数将看到一个空字符串。我注意到了潜在的缺陷,但认为在本例中不会发生这种情况,因为即使是空行也会有一个
    换行符
    ,如果最后一个文本行缺少
    换行符
    ,则必须至少有一个其他字符。但正如@chux所说,它可以。在@NisseEngström注释之后,这就是它不安全的原因。在最后一行之后没有
    换行符
    ,正确的3行被打印出来。在选择的情况下(嵌入空字符),
    strlen(buf)
    为0,因此
    if(bu
    
    buffer = (char*)malloc(bufferSize);
    while(fgets(buffer, bufferSize, file) != NULL) {
        //here store your pointer in array...
        buffer = (char*)malloc(bufferSize);
    };
    free(buffer);