我正在尝试在c中编写一个程序,其中我可以通过stdin的用户输入来控制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循环终止的原因。我在思考正确的方向吗?如果是,我怎么能摆脱这种额外的字符,在这种情况下是“回车”。
答案 0 :(得分:2)
更改此:
fgets(loop, 4, stdin);
对此:
fgets(loop, 5, stdin);
当然,在将缓冲区的大小设置为5之后,例如char loop[5]= "yes";
,为了存储单词“ yes”的3个字符,换行符fgets()
将会读取(因为是读行,对吧?)和字符串NULL终止符(如您所知)。
要解释代码的行为,您必须了解@DavidBowling的注释:
请注意,通过使用
fgets(loop, 4, stdin);
,当输入“是”时,换行符将留在输入流中,因此下一个输入呼叫将接听该换行符。
使用此程序演示:
#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)个字符。它读取y
,e
和s
,将它们从STDIN的缓冲区移到您声明的名为loop
的程序的缓冲区中,然后附加字符串NULL终止符。
现在STDIN缓冲区是:
------------------
| \n | | | |
------------------
并且在用户有机会输入之前,fgets(loop, 4, stdin);
将要执行(这样做是方法的职责,因为它们是STDIN缓冲区中等待消耗的数据-如果没有数据,那么该方法将耐心等待用户输入内容...)。
现在,它将换行符复制到loop
中,然后停止在此,因为现在STDIN缓冲区为空,并最终向loop
(在索引1)附加了字符串NULL终止符。
现在STDIN缓冲区为空:
-----------------
| | | | |
-----------------
由于用户没有更多输入-代码循环在while循环之后移动,因为当loop
是一个以换行符为第一个字符的字符串时,循环的条件为false。 >