如何在C语言中使用fgets()通过用户输入控制while循环的执行?

3

我正在尝试用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]: 

当我输入'no'时,会提示我是否继续循环,它停止了,这是应该的。但是,当我输入'yes'时,循环只执行一次就停止了。
我猜问题在于当我按下回车键时,fgets()将其存储到循环变量中,这就是为什么while循环终止的原因。我的想法正确吗?如果是,如何摆脱这个额外的字符,即在这种情况下是"Enter"键。

5
试着读取五个字符。请记住,fgets函数也希望读取换行符,并且只有四个字符的情况下没有足够的空间来存放它。 - Some programmer dude
3
在调用 fgets 后,您需要删除行尾换行符 - Weather Vane
5
请注意,使用fgets(loop, 4, stdin);时,在输入"yes"时会将换行符留在输入流中,因此下一个输入调用会捕捉到这个换行符。 - ad absurdum
谢谢大家,特别是@xing,你的建议非常清晰,我明白了我遇到的奇怪行为。 - Pankaj
1
在调用fgets()后,您可以使用strchr()搜索'\n',如果读取了'\n',则意味着输入缓冲区已清除,否则您可能需要“清除缓冲区”。 - Gam
1个回答

2

将其更改为:

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]: |
|

这段文字涉及IT技术,讲述了换行符在标准输入(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循环之后移动,当loop是以换行符作为其第一个字符的字符串时,循环条件求值为false。


PS:删除fgets()输入中的尾随换行符


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接