0

此链接说明了为什么feof()将其用作循环的退出指示器是一件坏事。

不安全 ==> 在 while 中进行feof()检查,在 while中进行检查fgets()

安全 ==>fgets()!=NULL在 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
4

3 回答 3

3

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

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

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

于 2014-12-13T20:28:31.343 回答
2

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

  1. 如果读取操作尝试读取文件末尾之后,该feof()函数将返回一个非零值。

  2. 函数testUnsafe()不检查的返回值,fgets()因此在满足条件之前重复先前读取的字符串feof()

我将您的功能复制到我的测试程序中

#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;
}

测试文件:

Line 1
Line 2
Line 3

输出testUnsafe()

Line 1 , 6
Line 2 , 6
Line 3 , 6
Line 3 , 6

输出testSafe()

Line 1 , 6
Line 2 , 6
Line 3 , 6
于 2014-12-13T20:22:26.740 回答
0

基本上,要阅读所有行,您必须使用这样的算法。在文件末尾没有换行符的情况下,您一定会加载所有行。

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

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

buffer = (char*)malloc(bufferSize);
while(fgets(buffer, bufferSize, file) != NULL) {
    //here store your pointer in array...
    buffer = (char*)malloc(bufferSize);
};
free(buffer);
于 2018-11-22T10:04:20.153 回答