#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才可以正常地增长,直到循环结束。
然后我又把这个程序稍微修改了下:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int i = 0;
char c;
for(i = 0; i < 5; i++)
{
scanf("%c", &c);
printf("%d ", i);
}
printf("\n");
system("PAUSE");
return 0;
}
测试时结果如下:a 0 1 b 2 3 c 4
刚开始我是很吃惊,我以为结果会是a 0 b 1 c 2 d 3 e 4的情形。仔细考虑下,输入字母后,字母会停留在缓冲区,因为缓冲区有数据,所以scanf函数不会等待用会输入数据,而是直接读取缓存区的数据。对于为什么每次输出两个数字后提示我输入字母,这个问题还没想清楚,可能与编译器有关吧。
于是我又修改了这个程序,在sacnf之前fflush了一把:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int i = 0;
char c;
for(i = 0; i < 5; i++)
{
fflush(stdin);
scanf("%c", &c);
printf("%d ", i);
}
printf("\n");
system("PAUSE");
return 0;
}
结果是a 0 b 1 c 2 d 3 e 4(这下正常了,呵呵)
最后,说下fflush(),并非所有的编译器都可以使用这个函数(gcc 就不支持),这个函数的移植性不好。
我们可以自己写代码来实现缓冲区的清空:
#include <stdio.h>
#include <stdlib.h>
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");
return 0;
}