C语言 字符串比预期的要长,并被视为多个输入

f0brbegy  于 2023-04-29  发布在  其他
关注(0)|答案(3)|浏览(101)

这是我在这里的第一篇文章,我对C语言相对较新(这只是我在大学的第二个单元)。
基本上,我正在尝试编写一段代码,询问用户是否希望继续。如果他们写“yes”,代码继续循环。如果他们写no,代码终止程序。如果他们写了别的东西,它只会再次询问,直到有一个可识别的输入。我正在使用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) :

看起来它几乎是保存了预期长度后的其余字符,并发送他们直接输入或什么?我想在保护字符串太长,但这不是理想的,在我看来。
我很抱歉,如果这个问题结构不好,任何建设性的批评都很感激。我在任何地方都找不到这个确切的问题,所以我想我应该问问自己。

62lalag4

62lalag41#

当你使用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;
}
bxjv4tth

bxjv4tth2#

看起来它几乎是保存了预期长度后的其余字符,并发送他们直接输入或什么?
是的,就是这样。
这些字符就在那里,坐在输入缓冲区中,等待被消费,就像前三个字符在一个时间点一样。
你从你的键盘发送字符,通过你的操作系统,进入你的终端。你的程序,按照你写的,将接受文本,直到宇宙的尽头(尽管一次三个字符)。只要有更多的字符可用,它就会吃掉它们,而不管你的击键在时间上分布得有多远。C++无法知道你想让它做什么。
也就是说,通过调整语义(如其他答案所示),可以获得更直观的调用/响应提示行为。

ltqd579y

ltqd579y3#

欢迎了解使用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();
}

(you也可以将其写成单个for语句,例如:for (int c = getchar(); c != '\n' && c != EOF; c = getchar()) {},但while通常更具可读性。)
这不仅仅是正确处理输入的问题。由于您希望强制用户输入“yes”或“no”,因此通常的方法是不断循环,直到满足输入条件。一些你在正确的轨道上,但没有完全到达那里。相反,您可以执行以下操作:

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");
}

(**注:**上述"yes""no"响应分别进行比较,以允许在"yes"exit上继续处理"no"

示例使用/输出

$ ./bin/scanf_yes_no

program processing....

Do you want to continue (yes/no): what?
error: invalid input.

Do you want to continue (yes/no): obnoxious long line because cat stepped on kbd
error: invalid input.

Do you want to continue (yes/no): yes

program processing....

Do you want to continue (yes/no): yes

program processing....

Do you want to continue (yes/no):
error: invalid input.

Do you want to continue (yes/no): no
that's all folks...

相关问题