C语言中scanf的一些问题
scanf与缓冲区
C语言没有输入输出关键字,其输入输出的操作是通过调用库函数实现的。C语言通过scanf函数读取键盘的输入(标准输入),当程序执行遇到scanf时,程序会阻塞,等到有输入时才继续执行。
程序执行时,如果遇到下面的代码:
int i = 0; //给int型i初始化并赋初值0
char j = 0; //空字符串
scanf("%d",&i);
printf("i = %d\n",i);
scanf("%c",&j)
printf("j = %c",j);
在执行时会出现要求输入字符时没有阻塞,直接输出空白的现象。如下图所示:
这是因为在scanf在处理整数型、浮点型、字符串的时候,会自动忽略空格,’\n’(回车)等字符;但是在处理字符型时不会忽略任何字符,因此语句在执行第一个scanf时输入了2和回车键,2会被读取走,回车键仍然停留在缓冲区(缓冲区的相关解释见下面补充)中,被第二个scanf读取,因此会输出“j = (回车)”。
此处补充缓冲区的一些原理:
缓冲区是内存中的一段空间,由操作系统分配。C语言缓冲区有三种情况:
-
全缓冲
在这种情况下,当填满标准I/O缓存后才进行实际I/O操作。全缓冲的典型代表是对磁盘文件的读写操作。
-
行缓冲
在这种情况下,当在输入和输出中遇到换行符时,将执行真正的I/O操作。这时,我们输入的字符先存放到缓冲区中,等按下回车键换行时才进行实际的I/O操作。典型代表是标准输入缓冲区(stdin)和标准输出缓冲区(stdout)。
-
不带缓冲区
也就是不进行缓冲,标准出错情况(stderr)是典型代表,这使得出错信息可以直接尽快地显示出来。
ANSI C(C89)要求缓存具有下列特征。
- 当且仅当标准输入和标准输出不涉及交互设备时,它们才是全缓存的。
- 标准出错绝不会是全缓存的。
在上面的例子中,就属于标准输入缓冲,我们在输入缓冲区放入的内容为字符(并不会把它当成整数型)“2\n”,在输出"\n"后,scanf才开始处理这串字符,"%d"匹配了整型(此处才把它当成整数型),然后放入变量i中,接着进行打印输出,这时’\n’仍然在标准输入缓冲区(stdin)内。被第二个scanf读取,产生如上图所示结果。
scanf函数的循环读取
有代码如下:
int main()
{
int i = 0;
int ret;
while((ret = scanf("%d",&i)) != EOF)
{
printf("i = %d\n",i);
}
return 0;
}
scanf的返回值和EOF的解释见下面的补充。
在执行该程序时,如果输入a,即当输入的类型错误时,scanf函数无法匹配成功,程序仍然会进入循环,这时会导致不断地重复打印 i = 0。因为其比配成功时,数据将会从缓冲器读出,而其匹配不成功,ret的值恒为0,不为-1,程序陷入循环。
为了避免这种情况,可以在while语句中加入语句如下:
while(fflush(stdin),(ret = scanf("%d",&i)) != EOF)fflush(stdin)
因为fflush函数具有刷新(清空)标准输入缓冲区的作用。
此处为scanf的返回值和EOF的解释补充:
scanf的返回值是匹配成功的个数,例如代码
int a = 0;
char b = 'a';
float c = 1.0;
int ret = 0;
ret = scanf("%d %c%f",&a,&b,&c); //此处的%c要加上空格,否则因为字符匹配时不会忽略任何字符,空格将会被 //视为字符输入,通过自己加一个空格的方式来避免这种错误
printf("%d\n",ret);
scanf 函数的返回值反映的是按照指定的格式符正确读入的数据的个数。如果都匹配成功那么将会scanf将会返回3,如果只有两个匹配成功那么将会返回2。
但是如果输入数据与指定格式不符,则会产生输入错误。遇到输入错误,scanf函数会立即终止,返回已经成功读取的数据的个数。
比如代码的scanf改成:
ret = scanf("%d%c%f",&c,&b,&a);
那么程序的运行结果为:
因为第一个输入的就不匹配,因此scanf在第一个字符处就终止,匹配成功0。
EOF:EOF意为End Of File代表了文件的结束,其值为-1,在程序执行时,用Ctrl+c来表示EOF。
计算机机试或者竞赛时的要求多个输入时注意事项:
可以使用如下代码来表示多个输入(比如两个),效果相同,否则将会报出Output Limit Exceeded(输出超出限制)的错误。
while(scanf("%d %d",&a,&b) != EOF)
while(scanf("%d %d",&a,&b) == 2)
while(~scanf("%d %d",&a,&b))
参考资料:
C语言scanf函数的返回值问题
【跟“龙哥”学C语言】
下一篇: 关于C语言编程时字符缓冲的一些问题与解答