【问题标题】:Empty stdin between fgets callsfgets 调用之间的空标准输入
【发布时间】:2017-01-11 23:23:53
【问题描述】:

我有一个代码,我希望 2 个用户输入最多 20 个字符。 我只想保留 20 个。我的问题是,在第一次输入之后,如果用户输入的字符超过 20 个,这些字符仍然在标准输入中,所以下一个 fget 会读取它。

  char *pseudo = malloc(21);
  fgets(pseudo,21,stdin);
  strtok(pseudo,"\n");

  char * tube = malloc(21);
  fgets(tube,21,stdin);
  strtok(tube,"\n");

我发现以下解决方案可以在 2 个 fgets 调用之间清空 stdin,它可以工作,但它会在 2 个调用之间阻塞:我必须输入一些内容才能被询问第二个输入。

int c = 0;
    while (c != '\n' && c != EOF)
    {
        c = getchar();
    }

【问题讨论】:

    标签: c stdin fgets


    【解决方案1】:

    你有几个问题:

    • 您的循环逻辑已损坏。
    • 如果您检测到您的输入行没有以换行符结尾,那么您应该只执行 fixed 循环,而这根本没有完成。

    所以像这个简单的例子:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int main()
    {
        char *pseudo = malloc(21);
        if (fgets(pseudo,21,stdin))
        {
            char *cr = strrchr(pseudo, '\n');
            if (cr == NULL)
            {
                int c;
                while ((c = fgetc(stdin)) != '\n' && c != EOF);
            }
            else
            {
                *cr = 0;
            }
        }
        else
        {
            *pseudo = 0;
        }
    
        char * tube = malloc(21);
        if (fgets(tube,21,stdin))
        {
            char *cr = strrchr(tube, '\n');
            if (cr == NULL)
            {
                int c;
                while ((c = fgetc(stdin)) != '\n' && c != EOF);
            }
            else
            {
                *cr = 0;
            }
        }
        else
        {
            *tube = 0;
        }
    
        printf("%s : %s\n", pseudo, tube);
    
        return 0;
    }
    

    输入

    01234567890123456789012345
    0123456789012345678
    

    输出

    01234567890123456789 : 0123456789012345678
    

    显然,您可以对其进行重构,将所有重复的代码放入一个或两个精心设计的函数中,但希望您能明白这一点。

    【讨论】:

    • 当然,strrchr(pseudo, '\n');fgets() 之后总是会提供与strchr(pseudo, '\n'); 相同的结果。你怀疑更好的性能strrchr()?我想可能有。
    • 由于 fgets 在输入末尾添加 '\n',使用 strrrchr 找到 '\n' 并不总是意味着我们读取了所有字符,不是吗?
    • @chux 老实说,我和你一样怀疑它是否会有所作为。与向前寻找非零值相比,rep 下的 scasb 可能会更快(类似于 strlen + 回退一个插槽并加载)是可行,但老实说,我从来没有花时间计算时钟周期。在解释这样的问题时,我通常使用strrchr,因为初学者更容易理解从字符串末尾向后搜索。如果它确实产生了性能差异,我会感到惊讶。
    • @StuYYY 谁告诉你fgets“在输入末尾添加'\n'”?它没有。如果它存在于输入流中(在进程中从所述相同的过程中消耗它)并且目标缓冲区中有可用空间,则它保留它。它不会凭空“添加”它。请参阅the documentation of fgets 并仔细阅读。
    • 确实我误解了 fgets 文档。效果很好,非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-07
    • 1970-01-01
    • 2018-05-09
    • 2014-12-28
    相关资源
    最近更新 更多