c语言scanf陷阱--缓冲区引起的跳过输入问题

小白在学习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)':

输入er
输入er

 这时候问题出现了

发现有个输入直接被跳过了
发现有个输入直接被跳过了

 我们原先设定好的第二次输入呢?????还留自动留下了一个空行!!??

????

3.问题解释:

其实在我们第一次输入并按下回车的时候,控制台一共获得了三个字符,分别是:e、r、回车(enter)。但是因为scanf()方法遇到非字符的时候会结束从控制台的获取,所以在输入'er'后,按下 '回车(enter)' 的同时,将'er'这个值以字符串的形式赋值给了类型为 'char' 的 'm' 数组,将使用过后的字符串: '回车(enter)' 保存在控制台输入的缓冲区,然后继续执行下一段输出代码,然后又要求用户输入。此时,因为上一次被使用过后的字符串被保存在缓冲区,现在scanf()方法从控制台的缓冲区获取上一次被使用过后的字符串,并只截取第一个字符: '回车(enter)' ,此时控制台缓冲区才算使用完了。。。。。。惊讶不?

所以在看似被跳过的输入,其实已经scanf()方法已经获取了我们的输入了,这个输入就是一个 '回车(enter)' ,只是跟我们理解的输入不一样罢了。

 

二、问题的解决:

1.在每次输入结束后使用getchar()方法:

我们要做的就是kill掉那个被使用剩下后保存在控制台输入缓冲区的字符串,使用getchar()方法(getchar()方法是解决目前问题的最简单的方法,至于getchar()方法特性,请自行查询),将在控制台输入缓冲区的使用剩下的字符销毁掉:其实就是从控制台获取字符,然后不使用从控制台输入缓冲区获取到的字符就算销毁了。当然,还可以使用清除缓存的方法,但是不适用于Linux系统

解决控制台的字符添加的getchar()方法
解决控制台的字符添加的getchar()方法

 

#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)'的话,我们的代码就不好使了:

在er后面加个空格
在er后面加个空格

 还是出现了自动跳过输入,

还是出现了自动输入
还是出现了自动跳过输入

由此得出,最后还是不要加空格的好!至于要是考虑出现最后加空格的情况,还是自行解决吧!

 

 

 

由此,大概已经明白了c语言缓冲区的特性了吧,如果有什么不明白滴地方欢迎评论哦!

 

 

 

 

  • 18
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值