天天看点

使用fflush清空缓冲区

在看《C陷阱与缺陷》时候,看到如下代码:

#include <stdio.h>

#include <stdlib.h>

int main(int argc, char *argv[])

{

  int i = 0;

  char c;

  for(i = 0; i < 5; i++)

  {

        scanf("%d", &c);

        printf("%d ", i);

  }

  printf("\n");

  system("PAUSE");   

  return 0;

}

    表面上看会输出0 1 2 3 4,可是测试的时候输出的却是1 0 2 0 3 0 a 1 2 3 4(红色字体为我输入的,以下相同)

    为什么?《C陷阱与缺陷》解释因为c的声名是char而不是int。当你令scanf()去读取一个整数时,它需要一个指向一个整数的指针。但这里它得到的是一个字符的指针。但scanf()并不知道它没有得到它所需要的:它将输入看作是一个指向整数的指针并将一个整数存贮到那里。由于整数占用比字符更多的内存,这样做会影响到c附近的内存。c附近确切是什么是编译器的事;在这种情况下这有可能是i的低位。因此,每当向c中读入一个值,i就被置零。当程序最后到达文件结尾时,scanf()不再尝试向c中放入新值,i才可以正常地增长,直到循环结束。

然后我又把这个程序稍微修改了下:

        scanf("%c", &c);

测试时结果如下:a 0 1 b 2 3 c 4

刚开始我是很吃惊,我以为结果会是a 0 b 1 c 2 d 3 e 4的情形。仔细考虑下,输入字母后,字母会停留在缓冲区,因为缓冲区有数据,所以scanf函数不会等待用会输入数据,而是直接读取缓存区的数据。对于为什么每次输出两个数字后提示我输入字母,这个问题还没想清楚,可能与编译器有关吧。

于是我又修改了这个程序,在sacnf之前fflush了一把:

        fflush(stdin);

结果是a 0 b 1 c 2 d 3 e 4(这下正常了,呵呵)

最后,说下fflush(),并非所有的编译器都可以使用这个函数(gcc 就不支持),这个函数的移植性不好。

我们可以自己写代码来实现缓冲区的清空:

int main( void )

     int i, c;

     for ( ; ; )

     {

          scanf("%d", &i);

          if ( feof(stdin) || ferror(stdin) )

          {

                break;

          }

         //没有发生错误,清空输入流。                

         //通过 while 循环把输入流中的余留数据“吃”掉

          while ( (c = getchar()) != '\n' && c != EOF ) ;

          //使用 scanf("%*[^\n]"); 也可以清空输入流,

          //不过会残留 \n 字符。                       

               printf("%d\n", i);

       }

       return 0;

       system("PAUSE");  

继续阅读