字符串比预期长,并被视为多个输入

问题描述 投票:2回答:3

这是我在这里的第一篇文章,我对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) :

似乎它几乎在预期的长度之后保存了其余的字符,并立即将它们发送到输入或什么?我希望能够防止太长时间的字符串,但在我看来这并不理想。

如果问题的结构很糟糕,我很抱歉,任何建设性的批评都会受到赞赏。我无法在任何地方找到这个确切的问题,所以我想我会问自己。

c string input protection
3个回答
0
投票

当你使用scanf("%3s", userInput)时,它只能读取由3终止到'\0'缓冲区的userInput字符。但是,如果键入的字符数超过3characters,则其余部分仍然存在于输入缓冲区中,等待scanfto读取它。你可以在每个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;
}

0
投票

似乎它几乎在预期的长度之后保存了其余的字符,并立即将它们发送到输入或什么?

是的,这正是发生的事情。

那些字符在那里,坐在输入缓冲区中,等待消耗,就像前三个字符在一个时间点一样。

您可以通过操作系统将键盘中的字符发送到终端。根据您编写的内容,您的程序将接受文本直到Universe结束(尽管一次只有三个字符)。只要有更多可用的字符,它就会吃掉它们,并且按键分配的时间并不重要。 C ++无法知道你希望它做什么。

话虽这么说,通过调整你的语义(如其他答案中所示),可以获得这样的调用/响应提示更直观的行为。


0
投票

欢迎使用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"
© www.soinside.com 2019 - 2024. All rights reserved.