不清楚stdin输入问题

时间:2015-06-20 04:20:23

标签: c buffer stdout stdin

我编写了一段代码,以帮助自己了解stdinstdout涉及的内容。

这是我的代码:

#include<stdio.h>
#include<stdlib.h>

void prompt(){
    int i=0;
    printf("please select:\n");                  //string1
    printf("1.input\n2.print\n3.Exit\n");        //string2
    scanf("%d",&i);
    switch(i){
        case 1:
            printf("Data input!\n");
            break;
        case 2:
            printf("data printed!\n");
            break;
        case 3:
            exit(0);
        case 10:
            printf("Newline detected!");                      //string3
        default:
            printf("Please input a valid number!(1-3)");    //string4
    }
}   

int main()
{
    while(1)
        prompt();

    return 0;
}

我希望此代码的作用是:

  1. 提示我输入;
  2. 然后我输入一个数字4,这是在案件之外;
  3. 因此默认大小写将匹配,字符串&#39;请输入有效的...&#39;(字符串4)将被打印。
  4. 因为在stdin缓冲区中仍然有一个换行符,在下一个循环中, 变量&#39; i&#39;将自动获取换行符,在ACSII中为10
  5. 因此,打印完毕后,请选择..1.input \ n2.print ....&#39; ,,检测到字符串&#39; Newline!&#39;(字符串3)将立即打印出来。
  6. 然后代码进入第三个循环,并提示我输入....
  7. 但这绝不会发生。我看不到任何&#39; Newline被检测到了!&#34;在输出中,即使我输入数字4,也不在案例中。

    任何人都可以详细说明此代码段的工作原理吗?

    顺便说一句:我原先假设当stdout中有东西打印时,stdin缓冲区将自动刷新。但有些事实证明我错了。我的假设是真是假?

    此外,当我输入一个字符(例如,一个g)而不是一个数字时,我在屏幕上无限地打印了字符串1,字符串2,sring 4 。那是为什么?

    ################################################## ##################### 3

    编辑:在查看答案后,我制作了另一个片段,以帮助理解。

    #include<stdio.h>
    #include<stdlib.h>
    
    void output();
    
    int main()
    {
        int i;
        printf("Enter a number here:\n");
        scanf("%d",&i);
    
        output();
    
        return 0;
    }
    
    void output(){
        char a;
        if (scanf("%c",&a)!=1){
            printf("scanf error!!");
            exit(1);
        }
        switch(a){
            case 'a':
                printf("an char a is entered");
                break;
            case 'b':
                printf("an char b is entered");
                break;
            default:
                printf("%c",a);
                printf("other thing is entered");
        }
    }
    

    无论你在第一次程序提示你时输入,你都不会得到第二次提示。例如,当程序第一次提示您时,如果输入数字4,那么您将获得换行符和字符串&#34;输入其他内容&#34;印在你的屏幕上。这是为什么?

3 个答案:

答案 0 :(得分:2)

  

因为在stdin缓冲区中仍然有一个换行符,在下一个循环中,变量'i'将自动获得换行符,在ACSII中为10

     

因此在打印完之后'请选择..1.input \ n2.print ....',会立即打印出一个字符串'Newline detected!'(字符串3)。

这是不正确的。当你使用

scanf("%d",&i);

忽略所有空格,包括换行符。

  

然后代码进入第三个循环,并提示我输入....

现在你知道它停留在第二个循环中,等待输入一个数字。

  

我原先假设当stdout中有东西打印时,stdin缓冲区将自动刷新。但有些事实证明我错了。我的假设是真是假?

这种假设是错误的。等待来自stdout的输入时,stdin会被刷新。

  

另外,当我输入一个字符(例如,一个g)而不是一个数字时,我得到字符串1,字符串2,在屏幕上无限打印4个。那是为什么?

那是因为程序在执行该行时无法读取该字符:

scanf("%d",&i);

字符保留在输入流中。您没有任何代码可以从输入流中删除该字符。这使程序保持无限循环。

答案 1 :(得分:1)

  

因为在stdin缓冲区中仍然有一个换行符   下一个循环,变量'i'将自动获得换行符   字符,在ACSII中是10

错误。 %d将获得一个整数,直到遇到换行符或空格,并且下一个scanf()

将不会使用缓冲区中的换行符。

因此请务必检查scanf()

的返回值
if(scanf("%d",&i) != 1)
{
 printf("scanf failed\n");
 return 1;
}

作为旁注:

    case 10:
        printf("Newline detected!");

此案例中缺少break

答案 2 :(得分:1)

解决问题中的第二个程序,这是一个温和的修订版本。它打印更多信息,并使用严格的原型。

#include <stdio.h>
#include <stdlib.h>

void output(void);

int main(void)
{
    int i;
    printf("Enter a number here:\n");
    if (scanf("%d", &i) == 1)
        printf("Read %d OK\n", i);

    output();

    return 0;
}

void output(void)
{
    char a;
    if (scanf("%c", &a) != 1)
    {
        printf("scanf error!!");
        exit(1);
    }
    printf("Character %d (%c) entered\n", a, a);
    switch (a)
    {
    case 'a':
        printf("an char a is entered\n");
        break;
    case 'b':
        printf("an char b is entered\n");
        break;
    default:
        printf("%c", a);
        printf("other thing is entered\n");
        break;
    }
}

示例运行:

$ ./stdin
Enter a number here:
23499911
Read 23499911 OK
Character 10 (
) entered

other thing is entered
$ ./stdin
Enter a number here:
2A
Read 2 OK
Character 65 (A) entered
Aother thing is entered
$ ./stdin
Enter a number here:
19b
Read 19 OK
Character 98 (b) entered
an char b is entered
$ ./stdin
Enter a number here:
999a
Read 999 OK
Character 97 (a) entered
an char a is entered
$

请注意,在第一次运行中,迷路字符是第二个1数字后面的换行符,字符代码为10.这是您应该得到的。

确保输出打印操作以换行符结束(以便及时显示)。如果不这样做,您的输出可能会无限期地保留。

  

您的意思是scanf()函数不会删除stdin缓冲区中的换行符吗?

scanf("%d", &i)肯定没有。 scanf("%c", &a)确实如此。当scanf()完成转换时,它会将不属于转换的字符放回到输入流中,为下一个输入操作做好准备。因此,无论数字后面是否有空格,字母或换行符,该字符是否已准备好进行下一个输入操作来读取它。大多数scanf()操作会跳过前导空格。有三个例外:%c%n%[…](扫描集)。他们不会跳过领先的空白区域。