这是我在这里的第一篇文章,我对C来说比较新(这只是我在大学的第二个单位)。
基本上,我正在尝试编写一段代码,询问用户是否希望继续。如果他们写“是”,代码继续循环。如果他们写否,则代码终止程序。如果他们写任何其他内容,它只会再次询问,直到有一个公认的输入。我正在使用scanf和printf,并尝试仅使用它们来创建此代码。
char userInput[4];
userInput[0] = '\0';
while ((strcmp(userInput, "yes") != 0) && (strcmp(userInput, "no") != 0))
{
printf("Do you want to continue (yes/no) :");
scanf("%3s", userInput);
}
我没有包含其余代码,只是为了简单起见。
例如,我的输入是
xxx
输出是
Do you want to continue (yes/no) :
这很好。但是,如果我输入:
xxxx
输出是:
Do you want to continue (yes/no) :Do you want to continue (yes/no) :
如果我输入
xxxxxxx
我明白了
Do you want to continue (yes/no) :Do you want to continue (yes/no) :Do you want to continue (yes/no) :
似乎它几乎在预期的长度之后保存了其余的字符,并立即将它们发送到输入或什么?我希望能够防止太长时间的字符串,但在我看来这并不理想。
如果问题的结构很糟糕,我很抱歉,任何建设性的批评都会受到赞赏。我无法在任何地方找到这个确切的问题,所以我想我会问自己。
当你使用scanf("%3s", userInput)
时,它只能读取由3
终止到'\0'
缓冲区的userInput
字符。但是,如果键入的字符数超过3
characters,则其余部分仍然存在于输入缓冲区中,等待scanf
to读取它。你可以在每个scanf
之后排出你的缓冲区,避免这种惊喜。
#include <stdio.h>
#include <string.h>
int main(void)
{
char userInput[4];
userInput[0] = '\0';
int c;
while ((strcmp(userInput, "yes") != 0) && (strcmp(userInput, "no") != 0))
{
printf("Do you want to continue (yes/no) :");
scanf("%3s", userInput);
while(1) // drain the input
{
c = getchar ();
if(c=='\n') break;
if(c==EOF) return -1;
}
}
return 0;
}
似乎它几乎在预期的长度之后保存了其余的字符,并立即将它们发送到输入或什么?
是的,这正是发生的事情。
那些字符在那里,坐在输入缓冲区中,等待消耗,就像前三个字符在一个时间点一样。
您可以通过操作系统将键盘中的字符发送到终端。根据您编写的内容,您的程序将接受文本直到Universe结束(尽管一次只有三个字符)。只要有更多可用的字符,它就会吃掉它们,并且按键分配的时间并不重要。 C ++无法知道你希望它做什么。
话虽这么说,通过调整你的语义(如其他答案中所示),可以获得这样的调用/响应提示更直观的行为。
欢迎使用scanf
进行用户输入的陷阱。 fgets
或POSIX getline
是更好的选择,因为它们避免了许多(“输入缓冲区中剩下什么?”)scanf
固有的问题。话虽这么说,知道如何正确使用scanf
很重要。
使用scanf
只不过是一个会计练习(1)实际上读了什么字符? (2)输入缓冲区中哪些字符未读?为了处理2号,你需要一些方法来清空在调用scanf
之间保留在输入缓冲区中的任何字符,以确保你没有被任何剩余的东西咬住。您还必须知道至少保留一个字符,否则您将只是阻止等待输入清除。清空stdin
的标准方法就是循环任何字符,直到你读到尾随的"\n'
(用户按“Enter”的结果)或EOF
。例如。,
void empty_stdin (void)
{
int c = getchar();
while (c != '\n' && c != EOF)
c = getchar();
}
(你也可以将它写成单个for
语句,例如,q。qxxswpoi,但while通常更具可读性。)
这不仅仅是妥善处理输入的问题。由于您要强制用户输入“是”或“否”,因此通常的方法是不断循环,直到满足输入条件。你在正确的轨道上的东西,但没有完全到达那里。相反,你可以这样做:
for (int c = getchar(); c != '\n' && c != EOF; c = getchar()) {}
如果以这种方式接近读取,则控制输入缓冲区中剩余的内容,不仅是循环中的每次读取,而且确保离开时用户输入中的缓冲区中没有剩余字符。
如上所述,正确使用scanf只是一个会计问题,一旦你知道每个格式说明符的行为,以及输入或匹配失败的效果在故障点停止读取,你可以回答(1)什么问题人物实际上是读过吗? (2)输入缓冲区中哪些字符未读?
一个简短的例子可以帮助:
char buffer[1024] = ""; /* don't skimp on buffer size */
for (;;) { /* loop continually */
int rtn; /* value to hold return from scanf */
printf ("Do you want to continue (yes/no): "); /* prompt */
rtn = scanf ("%1023[^\n]", buffer); /* read input */
if (rtn == EOF) { /* user canceled input, bail */
fprintf (stderr, "user canceled input.\n");
exit (EXIT_FAILURE);
}
else if (rtn == 1) { /* value stored in buffer */
/* check for input meeting criteria */
if (strcmp (buffer, "yes") == 0 || strcmp (buffer, "no") == 0) {
empty_stdin(); /* don't leave characters in stdin */
break; /* success, break input loop */
}
}
/* handle wrong input */
empty_stdin(); /* don't leave characters in stdin */
fprintf (stderr, "error: invalid input.\n\n");
}
(注意:上面的#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (void) {
char buffer[1024] = ""; /* don't skimp on buffer size */
for (;;) { /* process loop - doing stuff */
printf ("\nprogram processing....\n\n");
for (;;) { /* input - loop continually */
int rtn; /* value to hold return from scanf */
printf ("Do you want to continue (yes/no): "); /* prompt */
rtn = scanf ("%1023[^\n]", buffer); /* read input */
if (rtn == EOF) { /* user canceled input, bail */
fprintf (stderr, "user canceled input.\n");
exit (EXIT_FAILURE);
}
else if (rtn == 1) { /* value stored in buffer */
/* check for input meeting criteria */
if (strcmp (buffer, "yes") == 0) {
empty_stdin(); /* don't leave characters in stdin */
break; /* success, break input loop */
}
else if (strcmp (buffer, "no") == 0)
goto alldone;
}
/* handle wrong input */
empty_stdin(); /* don't leave characters in stdin */
fprintf (stderr, "error: invalid input.\n\n");
}
}
alldone:;
printf ("that's all folks...\n");
}
和"yes"
响应分别进行比较,以便继续在"no"
上进行"yes"
或exit
)
示例使用/输出
"no"