【问题标题】:How do you read scanf until EOF in C?您如何在 C 中读取 scanf 直到 EOF?
【发布时间】:2011-04-15 09:47:59
【问题描述】:

我有这个,但是一旦它到达假定的 EOF,它就会重复循环并再次 scanf。

int main(void)
{
        char words[16];

        while(scanf("%15s", words) == 1)
           printf("%s\n", words);

        return 0;
}

【问题讨论】:

  • 你用的是什么输入法?您是将文件重定向到stdin,还是在控制台输入?如果是后者,您使用的是什么操作系统以及如何输入 EOF?

标签: c scanf eof


【解决方案1】:

您需要根据EOF 而非1 检查返回值。

请注意,在您的示例中,您还使用了两个不同的变量名称,wordsword,只声明了 words,并没有声明它的长度,它应该是 16 以适应读入的 15 个字符加上一个NUL 字符。

【讨论】:

    【解决方案2】:

    试试:

    while(scanf("%15s", words) != EOF)
    

    您需要将scanf 输出与EOF 进行比较

    由于您在格式字符串中指定了 15 的宽度,因此您最多可以读取 15 个字符。所以单词 char 数组的大小应该是 1615 +1 代表 null char)。所以声明为:

    char words[16];
    

    【讨论】:

    • @user411313 不,scanf 可以返回 EOF ,因为他正在使用 != 进行比较,它不会第一次中断。但是,在一般情况下,您还需要分配项目的数量,以便进行一些验证。
    • @user411313:man scanf 和 C99 §7.19.6.2/16 都说它可以返回 EOF。
    • 这会产生相同的输出,[I am a sentence] [I] [am] [a] [sentence] 然后 scanf 再次开始......我希望它在这里中断。
    • 这个循环以字符串输入结束,因为所有字符(甚至是空字节)都被接受。如果转换使用的是数字类型(例如int d; while (scanf("%d", &d) != EOF) { … }),那么如果输入中有非数字、非空白字符(例如字母或标点符号),您将得到一个无限循环。总的来说,问题中的风格——while (scanf("…", &variable) == 1) 是最好的。我想知道为什么这对 OP 不起作用。 (也许Why does forking my process cause my file to read infinitely?
    【解决方案3】:

    Scanf 几乎总是比它的价值更麻烦。这里有两种更好的方法来做你想做的事情。第一个是或多或少直接翻译您的代码。它更长,但您可以查看它并清楚地看到它的作用,这与 scanf 不同。

    #include <stdio.h>
    #include <ctype.h>
    int main(void)
    {
        char buf[1024], *p, *q;
        while (fgets(buf, 1024, stdin))
        {
            p = buf;
            while (*p)
            {
                while (*p && isspace(*p)) p++;
                q = p;
                while (*q && !isspace(*q)) q++;
                *q = '\0';
                if (p != q)
                    puts(p);
                p = q;
            }
        }
        return 0;
    }
    

    这是另一个版本。通过检查很难看出这是做什么的,但如果一行长度超过 1024 个字符,它不会中断,所以这是我将在生产中使用的代码。 (嗯,真的我会在生产中使用tr -s '[:space:]' '\n',但这就是你实现类似东西的方式。)

    #include <stdio.h>
    #include <ctype.h>
    int main(void)
    {
        int ch, lastch = '\0';
        while ((ch = getchar()) != EOF)
        {
            if (!isspace(ch))
                putchar(ch);
            if (!isspace(lastch))
                putchar('\n');
            lastch = ch;
        }
        if (lastch != '\0' && !isspace(lastch))
            putchar('\n');
        return 0;
    }
    

    【讨论】:

    • 是的,这比for (char buf[1024]; scanf("%1023s", buf) == 1;) printf("%s\n", buf); 简单很多,除了你在某些情况下更改了前导、尾随和相邻空格的行为。
    • 在现实生活中,我会用我想要的空白行为(可能是也可能不是 OP 想要的——他们没有说),在单个字符上编写一个循环,但这会很多举个例子来说太乏味了。如果您使用的是 scanf ,则无论如何都不能关心边缘情况行为或错误恢复。
    • ...你知道吗,这不是太乏味了。重写示例。
    • 您的新示例更好,但它现在不完全等同于我上面的一行代码吗?如果是这样,为什么用 15 行替换一行(或两行,更有可能)?
    • 嗯,主要是因为我知道我的 15 行代码完全符合我的要求,而我不相信 scanf ever 能做到我想要。它的行为有太多奇怪的极端情况,尤其是在涉及错误处理时。
    【解决方案4】:

    您的代码循环,直到它读取一个单词,然后退出。因此,如果你给它多个单词,它会读取第一个单词并退出,而如果你给它一个空输入,它将永远循环。无论如何,它只会从未初始化的内存中打印随机垃圾。这显然不是你想要的,但你想要什么?如果您只想阅读并打印第一个单词(如果存在),请使用 if:

    if (scanf("%15s", word) == 1)
        printf("%s\n", word);
    

    如果你想循环,只要你能读一个单词,使用while:

    while (scanf("%15s", word) == 1)
        printf("%s\n", word);
    

    另外,正如其他人所指出的,您需要为单词数组提供足够大的大小以供您的 scanf:

    char word[16];
    

    其他人建议测试 EOF 而不是检查 scanf 匹配的项目数。在这种情况下这很好,除非存在 EOF,否则 scanf 不会匹配失败,但在其他情况下(例如尝试读取整数)不太好,其中 scanf 可能不匹配任何内容而不达到 EOF(如果输入不是t 一个数字)并返回 0。

    编辑

    看起来你改变了你的问题以匹配我运行它时工作正常的代码——循环读取单词直到达到 EOF 然后退出。因此,您的代码正在发生其他事情,可能与您如何按照 David 的建议输入输入有关

    【讨论】:

    • 您好,谢谢您的回复,但是您尝试过吗?我意识到我在原来的帖子上放了“!=”,但我的意思是 ==,这给了我我想要的东西,然后它再次调用我不想要的scanf。它称之为它让我无法摆脱循环。也许我的编译器?但唯一的问题是它打印了所有不会中断的单词。
    • @user315903:这就是为什么最好的办法是发布不起作用的代码,而不是尝试输入类似的内容。如果您的代码由于您不理解的原因而无法正常工作,那么您就无法理解问题所在,并且无法相信自己能够保留问题的本质。
    • 否;它不会在空输入上永远循环。如果没有数据要读取,scanf() 将返回EOF,而不是1,因此循环应该停止。
    【解决方案5】:

    对于 C 用户,这也可以工作

    while ( gets(str) != NULL )
    

    【讨论】:

    • 要明确,gets 的问题是它可以写​​入超出分配缓冲区的末尾。
    【解决方案6】:

    我想最好的方法是......

    int main()
    {
        char str[100];
        scanf("[^EOF]",str);
        printf("%s",str);
        return 0;     
    }
    

    【讨论】:

      【解决方案7】:

      伙计,如果您使用的是 Windows,则按 Enter 不会到达 EOF,而是在控制台按 Crtl+Z。这将打印“^Z”,一个 EOF 的指示符。 读取此内容时函数的行为(EOF 或 Crtl+Z):

      Function: Output: scanf(...) EOF gets(<variable>) NULL feof(stdin) 1 getchar() EOF

      【讨论】:

        猜你喜欢
        • 2010-09-17
        • 1970-01-01
        • 2020-10-24
        • 1970-01-01
        • 1970-01-01
        • 2017-07-16
        • 1970-01-01
        • 1970-01-01
        • 2023-03-06
        相关资源
        最近更新 更多