清空输入缓冲区&&处理错误输入的几种方法

Posted by Harid十二月 - 17 - 2010 Leave comments

编程的时候,我们有时候需要清空留在输入缓存区里面的一些我们不想要的数据。

通常我们遇到的问题是:程序在运行过程中会要求输入多次,然而首次输入后,在需要第二次输入的时候,我们没有输入程序就自动执行下去了。在 C 和 C++中,即使是输入时类型匹配,也有可能会发生这种情况。譬如在输入 char 类型的数据时,我们输入一个字符后回车,第二次输入时就被程序跳过了。另外就是在输入的数据类型与要求的类型不匹配时,并且不能按照语言中默认可以自动转换的顺序予以转换,则会发生同样问题。

先看几种易发生错误的写法

1、读取换行符跳过输入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
#include <stdlib.h>
int main()
{
    int inputA, inputB;
    printf("Input the first number(char):\n");
    scanf("%c", &inputA);
    printf("inputA = %d.\n", inputA);
    printf("Input the second number(char):\n");
    scanf("%c", &inputB);
    printf("inputB = %d.\n", inputB);
    getchar();
    return 0;
}

运行时错误如下图:

char_error

2、类型不匹配时读取其它字符跳过输入:

程序要求输入int型,输入时不小心输入了字符,如下图所示:

others_error

发生这类情况的原因是我们键盘键入的数据会保存在输入流中,而不是直接送给被赋值的变量。这样,当要求连续两次输入时,如果第一次的输入只读取了输入流的一部分,第二次输入时程序还能从输入流中读出东西,就会跳过让我们从键盘给值的过程。如上面所说第一种情况中第二次输入时就读取了一个回车符。

到目前为止,标准C/C++还没有能保证清空这一输入缓存区的函数,但是我们可以通过一些函数(C++习惯叫方法)的组合来解决这一问题。下面是几种方法,它们基本可以保证成功清空缓存区,并且在缓存区没有需要清除的数据时也能正常工作。这几种方法对于类型不匹配从而产生的输入错误,它们也能侦测到错误,并要求重新输入。其中用以清空缓冲区的部分包含在里面,有注释。我把它们按 C语言和C++区分开来。

一、C语言Linux && Windows平台:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <stdio.h>
int main()
{
    int inputA, inputB;
    int flag = 1;  /*标记是否输入类型匹配要求*/
    printf("Input the first number(int):\n");
    flag = scanf("%d", &amp;inputA);  /*scanf获得的值类型不匹配时返回0.*/
    /*如果输入类型不匹配,或者输入中含有非法字符时要求重输.第一次输入错时会要求继续按一个回车,第二次则不再需要.*/
    while(flag == 0 || getchar() != '\n')
    {
        setbuf(stdin, NULL);    /* Linux系统中用以清空缓冲区的函数.*/
        while (getchar() != '\n'); /*循环读取缓冲区中的字符*/
        printf("Input type error,please enter again: ");
        flag = scanf("%d", &amp;inputA);
    }
    printf("inputA = %d.\n", inputA);
    printf("Input the second number(int):\n");
    flag = scanf("%d", &amp;inputB);
    while(flag == 0 || getchar() != '\n')
    {
        setbuf(stdin, NULL);
        while (getchar() != '\n');
        printf("Input type error,please enter again: ");
        flag = scanf("%d", &amp;inputB);
    }
    printf("inputB = %d.\n", inputB);
    getchar();
    return 0;
}

运行示例如图:

instance_linux

二、C语言Windows平台:

在Windows平台下,将上面代码中的“setbuf(stdin, NULL); /* Linux系统中用以清空缓冲区的函数.*/”换为:

1
fflush(stdin);

也可以实现相同功能。

三、C++ Linux && Windows平台:

C++里面这种方法其实我一直在用,以前的几篇文章里就有:《C++模板类之堆排序》。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
int main()
{
    using namespace std;
    cout <<"Input the first number(int):\n";
    int inputA;
    /* 如果输入数据的类型不匹配,或者输入中含有非法字符,则清空缓存区并要求重输.*/
    while(!(cin >>inputA) || cin.get() != '\n')
    {
        cout <<"Input type error,please enter again: ";
        /*下面两句搭在一起使用可以有效清空缓存区.*/
        cin.clear();
        while(cin.get()!='\n')
            continue;
    }
    cout <<"\tinputA = "<<inputA<<endl;
        while(!(cin="">>inputB) || cin.get() != '\n')
    {
        cout <<"Input type error,please enter again: ";
        cin.clear();
        while(cin.get()!='\n')
            continue;
    }
    cout <<"\tinputB = "<<inputB<<endl;
    return 0;
}

运行示例如图:

instance_c_plus

四、C++ Windows平台:

在Windows平台,上面用以清空缓存区的两行可以替换为:

1
2
cin.clear();
fflush(stdin);

不过顺序不能变。

走过路过的朋友有什么更好的方法,希望不吝赐教。

   声明:本文采用 BY-NC-SA 协议进行授权 | 星期九
   原创文章转载请注明:转自《清空输入缓冲区&&处理错误输入的几种方法

  1. 😳 大叔,我好久没来勒,呜呜,,今天就特意来看你一个,不过话说要是没看到你的评论,我都不会那么早来了,看来回厦门了把你链接加上以后才好经常来、嘻嘻、、

  2. ❓ 不懂~我才开始学,你就弄这上来~ 😳 😮 ~看来收藏了,以后慢慢看~ 😉

    • @Kada, 有一个国外的论坛上看到说这个问题,于是总结了一下。一个不错的论坛,可以围观一下:http://cboard.cprogramming.com/c-programming/67891-flush-input-buffer.html

    • @Kada, 链接给错了,是这个:http://faq.cprogramming.com/cgi-bin/smartfaq.cgi?answer=1044873249&id=1043284392

  3. 代码高亮插件就是不爽。我现在都是用你给我推荐的fayaa.com/code/转成HTML再贴上来。

    • @Kada, 那个帖这种代码不太好,不可以缩进,帖一些短代码呀那个网站是非常不错。

      • @Harid, 你是说插件帮忙自动缩进吗?我都是自己控制好格式后再转换的。主要是如果代码太宽了,插件就产生一个滚动条,很烦。那个是给你换行了,还好点。

        • @Kada, 插件能自动缩进呀,只要粘贴代码的时候按格式在HTML模式下粘贴就能自动帮你缩进。
          那个滚动条的确是插件自作多情了。


分享按钮