【问题标题】:How to use fgets() to control the execution of while loop through user input in c?如何使用 fgets() 通过 c 中的用户输入来控制 while 循环的执行?
【发布时间】:2017-05-27 10:23:45
【问题描述】:

我正在尝试用 c 编写一个程序,其中我可以通过来自标准输入的用户输入来控制 while 循环的执行。我已经通过 scanf 和 getchar 函数成功地完成了它。现在我正在尝试使用广泛推荐使用的 fgets() 函数而不是 scanf() 函数来复制它。我写了以下代码:

#include<stdio.h>
#include<string.h>

int main()
{
 char loop[4]= "yes";

 printf("%s\n",loop);
 while(strcmp(loop,"yes")==0)
    {
     printf("Do you want to continue? [yes|no]: ");
     fgets(loop,4,stdin);
    }
}

在终端的输出中,我得到以下信息:

Do you want to continue? [yes|no]: yes
Do you want to continue? [yes|no]: 

我得到提示继续循环,当我输入“否”时,它应该停止,但只要我输入“是”,循环执行一次然后停止。

我想问题在于,一旦我按下回车,fgets() 就会将它存储到循环变量中,这就是 while 循环终止的原因。我在想正确的方向吗?如果是,在这种情况下,我怎样才能摆脱这个额外的字符,即“Enter”。

【问题讨论】:

  • 尝试改为读取 五个 个字符。请记住,fgets 也想读取换行符,并且只有四个字符,没有空格。
  • 您必须在致电fgets 后转至remove the trailing newline
  • 请注意,通过使用fgets(loop, 4, stdin);,当输入"yes" 时,换行符会留在输入流中,因此下一个输入调用会拾取这个换行符。
  • 谢谢大家,尤其是@xing,你的建议很清楚,我理解我得到的奇怪行为。
  • 在调用 fgets( ) 之后,你可以用 strchr( ) 搜索 '\n',如果 '\n' 被读取,则意味着输入缓冲区是干净的,否则你可能想要“清理缓冲区”。

标签: c fgets


【解决方案1】:

改变这个:

fgets(loop, 4, stdin);

到这里:

fgets(loop, 5, stdin);

当然,在将缓冲区大小设置为 5 之后,例如 char loop[5]= "yes";,为了存储单词“yes”的 3 个字符,换行符 fgets() 将读取(因为它是读取行,对吗?),以及字符串 NULL 终止符(如您所知)。


要解释代码的行为,你必须了解@DavidBowling 的评论:

请注意,通过使用fgets(loop, 4, stdin);,当输入“yes”时,换行符会留在输入流中,因此下一个输入调用会选择这个换行符。

使用这个程序来证明:

#include<stdio.h>
#include<string.h>

int main()
{
  char loop[4]= "yes";

  while(strcmp(loop,"yes")==0)
  {
    printf("Do you want to continue? [yes|no]: ");
    fgets(loop, 4, stdin);
    printf("|%s|\n",loop);    // I surrounded the output, in order to catch the newline
  }
  return 0;
}

输出:

Do you want to continue? [yes|no]: yes
|yes|
Do you want to continue? [yes|no]: |
|

这表明换行符留在标准输入 (STDIN) 缓冲区中,并在第二次调用 fgets() 时被消耗。从方法的参考:

从流中读取字符并将它们作为 C 字符串存储到 str 中,直到读取 (num-1) 个字符或到达换行符或文件结尾,以先发生者为准。

在复制到 str 的字符之后会自动附加一个终止空字符。

让我们一步一步来看看会发生什么:

您输入 yes,然后按 Enter,这会使标准输入缓冲区如下所示:

------------------
| y | e | s | \n |
------------------

现在对fgets(loop, 4, stdin); 的第一次调用被执行,这意味着该方法将尝试从STDIN 读取3 (4 - 1) 个字符。它读取yes,将它们从STDIN 的缓冲区移动到您声明的程序缓冲区,命名为loop,然后附加字符串NULL 终止符。

现在 STDIN 缓冲区是:

------------------
| \n |   |   |   |
------------------

在用户有机会输入之前,fgets(loop, 4, stdin); 将被执行(这是方法的职责,因为它们是在 STDIN 的缓冲区中等待消耗的数据 - 如果没有数据,那么方法会耐心等待用户输入一些东西...)。

现在,它将换行符复制到 loop 中,然后停在那里,因为现在 STDIN 缓冲区为空,并最终将字符串 NULL 终止符附加到 loop(在索引 1 处)。

现在 STDIN 缓冲区为空:

-----------------
|   |   |   |   |
-----------------

因为用户不再输入 - 代码流在 while 循环之后移动,因为循环的条件评估为 false,而 loop 是一个以换行符作为其第一个字符的字符串。


PS:Removing trailing newline character from fgets() input.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-25
    • 1970-01-01
    • 1970-01-01
    • 2016-07-13
    相关资源
    最近更新 更多