while循环中的两个scanf语句无法正常读取

时间:2015-11-17 17:07:13

标签: c loops while-loop scanf

首先发布在这里。我一直试图写一个非常简单的Knock Knock笑话。它如下:

敲!敲!

[用户输入]

香蕉!

[用户输入]

敲!敲!

[用户输入]

香蕉!

[用户输入]

......等等。 这是一个永无止境的笑话。 我的问题来自while循环中的scanf语句。如果我输入' a'对于第一次输入没有任何反应。如果我然后键入'一个' (前面的空间),它提出了香蕉!如果我输入' a'对于香蕉!,它将继续正确的笑话。

但是,如果我输入"那些"为了敲门!敲!提示它会继续香蕉!正确;但是,如果我输入" banana who"为香蕉!提示,如果结束说"敲门!敲门&#34!;并立刻"香蕉!"不允许输入"敲门!敲门&#34!;第二次通过循环提示。

以下是这些输入的图片: Picture

我错过了什么吗?我尝试过添加getchar()语句。我试过fflush(stdin)。我已经尝试将scanf作为一个功能,甚至为该函数添加了一个getchar()。我已将scanf("%s")更改为scanf("%s \ n"),这有助于但仍然无法正常运行。似乎第二个scanf试图将空格作为终止字符并从那里继续,但我不知所措。我只想做一个简单的永无止境的Knock Knock笑话。

我只是个白痴吗? 我做错了什么?

这是代码。

#include <stdio.h>

int main(void)
{
    while(1)
    {
        //Begin Joke
        printf("Knock! Knock!\n");
        scanf(" %s\n");                 //Who's there?

        //Second Part of Joke
        printf("Banana!\n");
        scanf(" %s\n");                 //Banana who?
    }
}

〜旋钮

3 个答案:

答案 0 :(得分:4)

如果你想阅读整行,

%s不是一个好主意;它通常会破坏任何空格字符。存在一些肮脏的黑客来规避这一点,但我建议您只使用fgets代替:

#include <stdio.h>

#define MAX_LINE_LEN 200

int main(void)
{
    char buf[MAX_LINE_LEN];

    while (1)
    {
        //Begin Joke
        printf("Knock! Knock!\n");
        fgets(buf, sizeof(buf), stdin);     //Who's there?

                                            //Second Part of Joke
        printf("Banana!\n");
        fgets(buf, sizeof(buf), stdin);     //Banana who?
    }
}

输出:

enter image description here


请注意,您在代码中执行的操作(scanf(" %s\n");)是未定义的行为 - %s需要有效的char缓冲区(足够长!),但是您没有提供。一般来说,scanf最好避免使用,因为它的错误处理能力很差。

答案 1 :(得分:1)

2个主要问题:"\n"之后无法保存输入和"%s"

改为使用fgets()

让我们撕开scanf(" %s\n");

一个。 " "指示scanf()读取和使用可选的空格(制表符,空格,'\n'等)。这一直持续到找到非白色空间。将char放回stdin

B中。 "%s"指示scanf() 1)读取并使用可选的空格2)读取并将无限量的非空白空间保存到 oops 缺少的字符数组中。 3)遇到空格时,将char放回stdin,将空字符附加到 oops 缺少的字符数组。

℃。 "\n"指示scanf()读取和使用可选的空格(制表符,空格,'\n'等)。这一直持续到找到非白色空间。将char放回stdin。 (就像步骤A一样。)

所以1)我们有未定义的行为,因为没有字符数组来保存数据。 2)即使使用如下的字符数组, scanf()也不会返回,直到第一次运行非空白区域后输入非空格(参见步骤C.) 。由于stdin缓冲,因此键盘输入一次出现。在输入2行之前,第一个scanf()将不会看到第二个单词。

char buf[100];
scanf(" %s\n", buf);  // better, but still not so good

如果的任何代码可能如下所示,但即使这样也有问题,因为它不会消耗输入的

char buf[100];
if (scanf("%99s", buf) != 1) Handle_Error();  // better

而是使用fgets()

char buf[100];
if (fgets(buf, sizeof buf, stdin) == NULL) Handle_Error();  // best

// lop off potential trailing \n if desired
buf[strcspn(buf, "\n")] = '\0';

答案 2 :(得分:-2)

来自cplusplus.com

  

附加参数应该指向已经分配的格式字符串中由其相应格式说明符指定的类型的对象。

所以提供一个参数:

while (1)
{
    char buffer[255];
    //Begin Joke
    printf("Knock! Knock!\n");
    scanf(" %s\n", buffer);                 //Who's there?

                                    //Second Part of Joke
    printf("Banana!\n");
    scanf(" %s\n", buffer);                 //Banana who?
}

请注意:

这个功能不安全,就像已经提到的那样可能会破坏。再次考虑使用fgets