所有输入都是先存放于缓冲区中,当按下回车(换行符也进入缓冲区中)时,告诉我们的程序:“输入暂时结束了,请去处理”,缓冲区中的数据被调用一次。
调用scanf等函数时,是从缓冲区读取。直到缓冲区内的数据读完了才等待用户再输入。
1,关于scanf
scanf的返回值为成功输入与格式控制符成功匹配并被读入变量的个数。如果没有数据被成功读入,返回值为0。要善于使用scanf的返回值。
-
格式控制符中的非空白字符(逗号等)一定要和输入流中的下一个字符匹配上,如果不匹配,scanf函数会失败并且退出,之后的输入都没有读取成功。
-
如果格式控制符中含有空白字符(空格、tab、换行),则scanf会从stdin缓冲区中读入并忽略掉所有的空白字符,直到遇到一个非空白字符为止。
-
如果格式控制字符中含有格式说明符,scanf会根据格式从stdin中读入数据,此时有3种情况被认为是数据输入结束:
- 在stdin缓冲区中遇到空白字符
- 遇到与格式说明符不同的非法字符输入
- 达到输出域宽时
1,输入单个字符时
%c前有空格时scanf(" %c", &a);
scanf从缓冲区中第一个非空白字符开始读取,即无论输入多少空格、回车、制表都没有用。
%c前没有空格时scanf("%c", &b);
则键盘输入的都能被scanf读取(包括换行、空格、制表),相当于getchar()。
最后输入的回车也存在于缓冲区中。
2,输入数字时
空格、回车、制表 会使一次输入结束
double型浮点数只能用%lf来输入(%lf也只能用来输入double型浮点数),输出时用%f、%lf均可。总之一定要使用与数据类型对应的正确的格式修饰符 。这是因为scanf接受的只是参数的地址,必须要有正确的格式修饰符才能确定存储的格式。
3,输入字符串时
与gets不同,scanf会忽略所输入的字符串前面的空白字符,也不会读入字符串后面的空白字符,而把字符串后面的空白字符作为输入结束的标志。
scanf读取字符串时不能读取换行符。
char str1[20], str2[20], c;
scanf("%s", str1);
c = getchar();//输入str1时最后的换行符仍保留在缓冲区,可以作为单个字符被直接读入
//但若之后接着为用scanf输入另一个字符串,则输入str1时最后的换行符不能进入字符串str2,因此str2[0]不为换行符。
//输入的换行符会积累在缓冲区中
因此在使用完scanf后,用getchar来消化或用while(getchar()!='\n')
(万能),或者在scanf中加入一个\n 即scanf("%d\n", &n);
也可以在scanf之后用fflush(stdin);
(这种方法不具有移植性)以清空缓冲区。
使用scanf函数时要特别注意缓冲区的问题。
int i;
do {
printf("*");
scanf("%d", &i);//输入a
if (i == 1) break;
} while (1);
return 0;
例如该程序,若输入a,则由于格式不匹配,scanf读取会失败,结束读入,但它不会从缓冲区中读走不匹配数据,也就是说a将一直留在缓冲区。由于缓冲区不为空,因此程序也不会停下来等待用户输入,用户也就没有机会再输入1。i没有被赋值,只是一个随机数。scanf会退出再判断再读取缓冲区再退出…程序陷入了死循环。
为了解决这个问题,我们可以利用scanf函数的返回值