c语言scanf陷阱--缓冲区引起的跳过输入问题
小白在学习c语言的时经常会有不懂的地方,有时候因为一个小小的问题,或者因为一个小小的概念没有理解清楚,都会造成懵逼、无解的情况,然而这样的情况在编程中经常出现,所以不不仅在c语言中,还存在大多数的编程语言中:本文要说的就是关于c缓冲区特性引发scanf()方法的一些奇怪现象:本文开始:1.本文描述的编译环境均在虚拟机Linux-centos7系统下运行2.本文从编译到运行均使用 Lin...
小白在学习c语言的时经常会有不懂的地方,有时候因为一个小小的问题,或者因为一个小小的概念没有理解清楚,都会造成懵逼、无解的情况,然而这样的情况在编程中经常出现,所以不不仅在c语言中,还存在大多数的编程语言中:本文要说的就是关于c缓冲区特性引发scanf()方法的一些奇怪现象:
本文开始:
1.本文描述的编译环境均在虚拟机Linux-centos7系统下运行
2.本文从编译到运行均使用 Linux Root 账户操作
3.本文编译软件使用的是 Linux gcc 编译器
4.本文使用的文本编辑器是 Linux vim
5.解决问题的关键方法 : getchar()
本文参考书刊:《c primer plus(第6版)中文版》 第92页4.4.5 使用scanf() >>> 1.从scanf()角度看输入
本文参考博文:
本文重要概念:
1.在控制台获取的输入时,任何输入都将视为字符,包括 '回车(enter)' 键也是一个字符
2.使用scanf()方法,在输入格式使用%c时,只会获取第一个字符,如果第一个字符时空白,则跳过空白获取下一个字符,以此往复
3.按照scanf()方法获取字符串的规则,如果scanf获取完后就会停止截取字符,并将剩下的字符保存在缓存区,作为下次scanf()方法从控制台获取字符串的输入
正文开始:
一、问题的出现:
1.出现条件:
通常在开始学编译c语言的时候,初学者都要在控制台使用scanf()方法与用户交互,而且使用了多个scanf()方法与用户进行交互,发现有需要用户第二次输入单个字符或字符串的时候会出现问题。
比如:上个scanf()方法要求从控制台获取一个字符输入或字符串输入,此时按照scanf()方法的规则,在开头遇到空白(空格)则自动跳过去获取下一个字符或字符串,在获取字符或字符串完成后,如果后面有空白(空格)则结束获取字符或字符串,此时的问题是:空白(空格)后面还有字符怎么办?还有空白(空格)本身也是一个字符,'回车(enter)'键也是一个字符。
此时,被使用过后的台输入字符,将剩下的字符或字符串(包括空格和‘回车(enter)’在内的字符)保存在缓冲区,作为下次scanf()方法从控制台获取字符或字符串的输入
#include <stdio.h> //代码手动写的,可能会出错,谨慎复制!
int main(void)
{
char m[40];
char n;
printf("please input frist str:\n"); //提示用户输入第一个字符串
scanf("%s",&m); //获取用户第一个输入字符串
printf("you input str is :%s\n",m); //输出用户的输入的第一个字符串
printf("input second char :\n"); //提示用户输入第二个字符
scanf("%c",&n); //获取用户的第二个字符
printf("now you input second char is :%c\n",n);//输出用户输入的第二个字符
return 0;
}
2.问题现象:
比如我编译刚刚写好的代码
#gcc -o two two.c
没有报错,然后我们运行当前目录下编译好的two文件
#./two
然后要求输入第一个字符串,我们输入er,按下'回车(enter)':
这时候问题出现了
我们原先设定好的第二次输入呢?????还留自动留下了一个空行!!??
3.问题解释:
其实在我们第一次输入并按下回车的时候,控制台一共获得了三个字符,分别是:e、r、回车(enter)。但是因为scanf()方法遇到非字符的时候会结束从控制台的获取,所以在输入'er'后,按下 '回车(enter)' 的同时,将'er'这个值以字符串的形式赋值给了类型为 'char' 的 'm' 数组,将使用过后的字符串: '回车(enter)' 保存在控制台输入的缓冲区,然后继续执行下一段输出代码,然后又要求用户输入。此时,因为上一次被使用过后的字符串被保存在缓冲区,现在scanf()方法从控制台的缓冲区获取上一次被使用过后的字符串,并只截取第一个字符: '回车(enter)' ,此时控制台缓冲区才算使用完了。。。。。。惊讶不?
所以在看似被跳过的输入,其实已经scanf()方法已经获取了我们的输入了,这个输入就是一个 '回车(enter)' ,只是跟我们理解的输入不一样罢了。
二、问题的解决:
1.在每次输入结束后使用getchar()方法:
我们要做的就是kill掉那个被使用剩下后保存在控制台输入缓冲区的字符串,使用getchar()方法(getchar()方法是解决目前问题的最简单的方法,至于getchar()方法特性,请自行查询),将在控制台输入缓冲区的使用剩下的字符销毁掉:其实就是从控制台获取字符,然后不使用从控制台输入缓冲区获取到的字符就算销毁了。当然,还可以使用清除缓存的方法,但是不适用于Linux系统
#include <stdio.h> //代码手动写的,可能会出错,谨慎复制!
int main(void)
{
char m[40];
char n;
printf("please input frist str:\n"); //提示用户输入第一个字符串
scanf("%s",&m); //获取用户第一个输入字符串
getchar(); //解决掉第一次获取后留下的'回车(enter)'字符
printf("you input str is :%s\n",m); //输出用户的输入的第一个字符串
printf("input second char :\n"); //提示用户输入第二个字符
scanf("%c",&n); //获取用户的第二个字符
printf("now you input second char is :%c\n",n);//输出用户输入的第二个字符
return 0;
}
现在看来已经解决了跳过输入的问题了:
但是使用一次getchar方法只能kill掉一个字符,如果我们子在输入 'er' 的时候,后面再加一个'空格(\0)'的话,我们的代码就不好使了:
还是出现了自动跳过输入,
由此得出,最后还是不要加空格的好!至于要是考虑出现最后加空格的情况,还是自行解决吧!
由此,大概已经明白了c语言缓冲区的特性了吧,如果有什么不明白滴地方欢迎评论哦!
更多推荐
所有评论(0)