C 字符串比预期的长,并被视为多个输入
这是我在这里的第一篇文章,我对C比较陌生(这只是我在大学的第二个单元) 基本上,我正在尝试编写一段代码,询问用户是否希望继续。如果他们写“是”,代码将继续循环。如果他们写“否”,则代码终止程序。如果他们写了其他东西,它只会再次询问,直到有可识别的输入。我正在使用scanf和printf,并试图仅使用它们来创建此代码C 字符串比预期的长,并被视为多个输入,c,string,input,protection,C,String,Input,Protection,这是我在这里的第一篇文章,我对C比较陌生(这只是我在大学的第二个单元) 基本上,我正在尝试编写一段代码,询问用户是否希望继续。如果他们写“是”,代码将继续循环。如果他们写“否”,则代码终止程序。如果他们写了其他东西,它只会再次询问,直到有可识别的输入。我正在使用scanf和printf,并试图仅使用它们来创建此代码 char userInput[4]; userInput[0] = '\0'; while ((strcmp(userInput, "yes") != 0) &&
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
进行用户输入的陷阱fgets
或POSIXgetline
是更好的选择,因为它们避免了scanf
固有的许多问题(“输入缓冲区中还有什么?”)。尽管如此,重要的是要知道如何正确使用scanf
使用scanf
只不过是解释(1)实际读取了哪些字符的练习?(2)输入缓冲区中哪些字符未读?为了处理第二个问题,您需要在调用scanf
之间清空输入缓冲区中剩余的字符,以确保不会被剩余的字符咬伤。您还必须知道,至少有一个字符仍然存在,否则您将只是阻塞等待输入清除。清空stdin
的标准方法是循环任何剩余字符,直到您读取尾随的“\n”
(用户按“Enter”键的结果)或EOF
。例如
void empty_stdin (void)
{
int c = getchar();
while (c != '\n' && c != EOF)
c = getchar();
}
(您也可以将其作为一个for
语句编写,例如for(int c=getchar();c!='\n'&&c!=EOF;c=getchar()){}
,但while通常更具可读性。)
这不仅仅是正确处理输入的问题。由于您想强制用户输入“是”或“否”,一般的方法是不断循环,直到满足输入条件。有些事情您已经走上了正确的轨道,但还没有完全实现。相反,您可以做:
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");
}
如果以这种方式进行读取,则可以控制输入缓冲区中剩余的内容,不仅是循环中的每次读取,还可以确保离开时用户输入的缓冲区中没有字符
如上所述,正确使用scanf只是一个会计问题,一旦您知道每个格式说明符的行为,以及输入或匹配失败在失败点停止读取的影响,您就可以回答以下问题:(1)实际读取了哪些字符?和(2)哪些字符在输入缓冲区中保持未读状态
举个简单的例子可能会有所帮助:
#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");
}
当您使用scanf(“%3s”,userInput)
时,它将只读取3个以'\0'
结尾的字符到userInput
缓冲区。但是,如果您键入的字符超过3个,其余字符仍在输入缓冲区中,等待scanf
读取。
您可以在每次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;
}
#包括
#包括
内部主(空)
{
字符用户输入[4];
用户输入[0]='\0';
INTC;
而((strcmp(userInput,“yes”)!=0)和&(strcmp(userInput,“no”)!=0))
{
printf(“是否继续(是/否):”;
scanf(“%3s”,用户输入);
while(1)//耗尽输入
{
c=getchar();
如果(c=='\n')中断;
如果(c==EOF)返回-1;
}
}
返回0;
}
看起来它几乎是在预期长度之后保存其余的字符,然后直接将它们发送到输入端还是什么
是的,事情就是这样
这些字符就在那里,坐在输入缓冲区中,等待被消费,就像前三个字符在一个时间点上一样
您可以通过操作系统将字符从键盘发送到终端。根据您编写的内容,您的程序将接受文本,直到世界末日(尽管一次三个字符)只要有更多的字符可用,它就会吃掉它们,而且你的按键敲击时间有多远,这并不重要。C++没有办法知道你想让它做任何其他事情。
也就是说,通过调整语义(如其他答案所示)对于这样的呼叫/响应提示,可以获得更直观的行为。scanf
一次只读取3个字符,其余的字符保留在输入缓冲区中。因此,下次调用scanf
时,会看到剩余的字符,并立即读取它们。任何事情都不要使用scanf
。读取整行inp使用fgets
(或者更好,但不是普遍可用的,getline
),然后手动解析——在本例中,这意味着去除空白,然后与“是”或“否”进行比较。您可以使用read,这是更好地理解/了解其工作原理的方法”看起来它几乎是在预期长度之后保存其余的字符,并直接将它们发送到输入端或其他什么?”这不是“看起来如此”,这正是正在发生的事情。为什么要“它”“放弃任何输入?如果你的应用程序不需要这些输入,你有责任阅读并丢弃它。我对它还是个新手
#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;
}