-
scanf()函数有返回值,且返回值是正确读取的个数
scanf("%d%d", &x, &y);- 若是x,y都被正确读取了,则返回值是2;
- 若只有x被正确读取了,则返回值是1;(不存在x没有被正确读取,但是y被正确读取的情况)
- 若x,y都没有被读取,则返回值为0;
- 若是遇到错误或者文件末尾,则返回-1,这个-1就是常见的E0F(end of file),他俩等价;
-
scanf是从缓存区读取数据的
- 每成功读取就会把缓存区的该数据删掉;
- 若是需要读取但是缓存区还没有值,scanf就会一直等待用户输入(阻塞)直到用户输入;
- 若是读到不是scanf需要的值,scanf不会清空缓存,会继续接着读,除非缓存里面是scanf需要的值。
-
scanf对不同类型输入的处理方式
前提:空格、回车、制表符Table都是空白字符;-
对于%d类型的输入,scanf默认的分割符是所有的空白字符。也就是说如果一个scanf函数中出现scanf("%d%d",&a,&b),那么用任何一个空白字符来分隔两个整数a,b的值,变量a,b都可以接收到正确的输入。且scanf会忽略输入数据项前面的空白字符。
-
对于%c类型的输入,scanf默认所有字符都是需要接收的字符,包括所有的空白字符也会被接收。也就是说如果一个scanf函数中出现scanf("%c%c",&a,&b),那么输入
c t
,最后a是c
,b是,
t
是接收不了的; -
对于%s类型的输入,scanf默认的分割符是所有的空白字符。scanf对于字符串输入的处理和对整数类似,会忽略前导的空白字符,而且默认的分隔符是所有的空白字符。
- 这里需要详细讲一下
- 比如scanf("%[^\n]",s);
这句代码的意思是除了回车键,其余都接收放进s字符串里面。如果你打了回车,回车不会被接收进字符串s里面,回车之前的所有字符包括空格都会被放进字符串s里面。
- 那么,这个回车呢?它会一直被留在缓存里面,只要不动这个缓存,他会一直在。此时scanf的返回值是1(如输入:abc\n)或者0(如输入:\n)。
- 上面的代码不会有任何问题,但是一旦写了写了下面的代码,就会出错。while(scanf("%[^\n]", s) != EOF){ printf("%s", s); }
原因是:scanf("%[^\n]", s)接收非回车符,一旦碰到回车就停止,然后进入循环里面执行。但是缓冲区里面的
\n
一直在,没有被读取之后删除,scanf("%[^\n]", s)的返回值一直是0或者1,while循环里面一直成立,scanf一直在尝试读取非回车符,但是一直遇到缓存里面的回车符,每遇到一次刚刚的回车符就printf("%s", s)以下之前输入的值,就会出现无限循环输出… -
-
缓冲区数据的读取
像第3点那样,出现回车一直呆在缓冲区消不掉怎么办?- 第一种方法:使用fflush(stdin);主动清空缓冲区
while(scanf("%[^\n]", s) != EOF){ fflush(stdin); printf("%s", s); }
- 第二种方法:使用getchar()函数,主动吞掉缓冲区的第一个字符,也就是卡住的那个回车字符
while(scanf("%[^\n]", s) != EOF){ getchar(); printf("%s", s); }
- 第三种方法:不使用
scanf("%[^\n]", s)
使用gets()函数,gets()函数会把回车和EOF当成分隔符,但是不具备对缓冲区的一些操作,所以用来处理字符串好,但是改成其他的分隔符就不太好用了,但是不具有通用性。
- 第一种方法:使用fflush(stdin);主动清空缓冲区
可以用以下代码做测试。
附录1:
#include<stdio.h>
int main(){
char s[100];
while(scanf("%[^\n]", s) != EOF){
//fflush(stdin);
//getchar();
printf("%s", s);
}
return 0;
}
附录2:
可以参考这位博主的博客理解。https://blog.csdn.net/xia7139/article/details/14522493