当字符遇上 scanf() 要当心
当字符遇上 scanf() 要当心
看一下程序
char ch1,ch2;
printf("请输入ch1,ch2的值:");
scanf("%c %c",&ch1,&ch2);
printf("ch1 = %c, ch2 = %c\n",ch1,ch2);
printf("请再次输入ch1的值:");
scanf("%c",&ch1);
printf("请再次输入ch2的值:");
scanf("%c",&ch2);
printf("ch1 = %c, ch2 = %c\n",ch1,ch2);
运行结果如下:

第二次输出为什么会出现异常情况呢 ?
这里有两个问题
- 为什么出现了
请再次输入ch1的值:请再次输入ch2的值:的情况,按照原本的预测请应该是先出现请再次输入ch1的值:,键盘输入了一个字符之后再出现请再次输入ch2的值:,键盘再输入一个字符 - 为什么第二次输入ch1,的值后,直接就输出了ch1 和ch2 ,而且 ch1 = '\n', ch2 = 'C'?
第一个问题
首先需要知道CPU 的工作原理
由于输入设备和输出设备对于数据的读写速度比较慢,CPU为了降低输入输出次数,提高运行效率,避免长时间的等待,所以内核就在内存中提供了一块空间作为缓冲区,( 缓冲区也可以称为缓存(Cache),是属于内存空间的一部分。)
每当使用读操作函数,试图将数据读取出来时,数据都会流过标准*输入缓冲区*,然后再在适当的时刻冲洗(或称刷新,flush)到内核缓冲区,最后才真正得到数据。
所以CPU 并不是没每时每刻都在读取数据,而是在满足刷新条件时才会从出入缓冲区读取数据。刷新条件按形式分为三种:全缓冲、行缓冲、无缓冲。
全缓冲:指的是当缓冲区被填满就立即把数据冲刷到文件、或者在关闭文件、读取文件内容以及修改缓冲区类型时也会立即把数据冲刷到文件,一般读写文件的时候会采用
无缓冲:指的是没有缓冲区,直接输出,一般linux系统的标准出错stderr就是采用无缓冲,这样可以把错误信息直接输出。
行缓冲:指的是当缓冲区被填满(一般缓冲区为4KB,就是4096字节)或者缓冲区中遇到换行符’\n’时,或者在关闭文件、读取文件内容以及修改缓冲区类型时也会立即把数据冲刷到文件中,一般操作IO设备时会采用,比如printf函数就是采用行缓冲。
知道了CPU 工作原理之后,我们就知道了printf() 函数的刷新条件有四个:
- 程序结束;
- 遇到换行 ‘\n’;
- 缓冲区满;
- 利用函数fflush() 手动刷新.
这也就解释了为什么出现 请再次输入ch1的值:请再次输入ch2的值:的情况,是因为没有遇到刷新条件,所以在写程序时,非必要情况都需要加上换行‘\n’。
第二个问题
在解释CPU 工作原理是说过 Linux 系统读取数据,是先从键盘进入到输入缓冲区,再进入到内核缓冲区,最后读取到数据。所以在第一次输入ch1 ,ch2 的值为A B<手动输入'\n' ,缓冲区应该是字符串
"A B\n", CPU 先读取“A B”,光标位置在字符B 的后面,当再次从缓冲区读取字符型数据时读出来的是字符‘\n’ ,ch1 = '\n', ch2 读取的是后面输入的字母C 。
那么我们如何解决这个问题呢?
在读取字符之前先要清空缓冲区,使用函数getchar() ,让光标后移到正确的位置,如下:
char ch1,ch2;
printf("请输入ch1,ch2的值:");
scanf("%c %c",&ch1,&ch2);
printf("ch1 = %c, ch2 = %c\n",ch1,ch2);
getchar(); //读取换行符
printf("请再次输入ch1的值:");
scanf("%c",&ch1);
getchar(); //读取换行符
printf("请再次输入ch2的值:");
scanf("%c",&ch2);
printf("ch1 = %c, ch2 = %c\n",ch1,ch2);

当字符遇上 scanf() 要当心的更多相关文章
- 前端遇上Go: 静态资源增量更新的新实践
前端遇上Go: 静态资源增量更新的新实践https://mp.weixin.qq.com/s/hCqQW1F8FngPPGZAisAWUg 前端遇上Go: 静态资源增量更新的新实践 原创: 洋河 美团 ...
- DP在字符匹配上的实现
在此保存下近段时间做的DP在字符匹配上的实现的题目 对于不同的字符串来说,2者只能不断将下标往后推移来实现匹配从而得到的最大匹配数 如 abcd 和 dcba 这个最大匹配数只能为1,因为两个d匹配后 ...
- html实体编码遇上js代码
单双引号 在js代码中 在js中单.双引号引起来的是字符串,如果我们要在字符串中使用单.双引号,需要反斜杠进行转义 let str='user\'s name'; // or let str=&quo ...
- MVC遇上bootstrap后的ajax表单模型验证
MVC遇上bootstrap后的ajax表单验证 使用bootstrap后他由他自带的样式has-error,想要使用它就会比较麻烦,往常使用jqueyr.validate的话只有使用他自己的样式了, ...
- 敏捷遇上UML-需求分析及软件设计最佳实践(郑州站 2014-6-7)
邀请函: 尊敬的阁下:我们将在郑州为您奉献高端知识大餐,当敏捷遇上UML,会发生怎样的化学作用呢?首席专家张老师将会为您分享需求分析及软件设计方面的最佳实践,帮助您掌握敏捷.UML及两者相结合的实 ...
- 敏捷遇上UML—软创基地马年大会(广州站 2014-4-19)
我们将在广州为您奉献高端知识大餐,当敏捷遇上UML,会发生怎样的化学作用呢?首席专家张老师将会为您分享需求分析及软件设计方面的最佳实践,帮助您掌握敏捷.UML及两者相结合的实战技巧. 时间:2 ...
- 敏捷遇上UML——软创基地马年大会(深圳站 2014-3-15)
邀请函: 尊敬的阁下: 我们将在深圳为您奉献高端知识大餐,当敏捷遇上UML,会发生怎样的化学作用呢?首席专家张老师将会为您分享需求分析及软件设计方面的最佳实践,帮助您掌握敏捷.UML及两者相结合的实战 ...
- 初识genymotion安装遇上的VirtualBox问题
想必做过Android开发的都讨厌那慢如蜗牛的 eclipse原生Android模拟器吧! 光是启动这个模拟器都得花上两三分钟,慢慢的用起来手机来调试,但那毕竟不是长久之计,也确实不方便,后来知道了g ...
- SQL SERVER 2008 R2 SP1更新时,遇上共享功能更新失败解决方案
SQL SERVER 2008 R2 SP1更新时,遇上共享功能更新失败的问题,可作如下尝试: 更新失败后,在windows的[事件查看器→应用程序]中找到来源为MsiInstaller,事件ID为1 ...
- 当创业遇上O2O,新一批死亡名单,看完震惊了!
当创业遇上O2O,故事就开始了,总投入1.6亿.半年开7家便利店.会员猛增至10万……2015半年过去后,很多故事在后面变成了一场创业“事故”,是模式错误还是烧钱过度?这些项目的失败能给国内创业者带来 ...
随机推荐
- #线性dp,排列组合#洛谷 2476 [SCOI2008]着色方案
题目 分析(弱化版) 最暴力的想法就是直接维护每种颜色的个数dp, 弱化版有一个很突出的地方就是 \(c_i\leq 5\), 也就是说可以将相同个数的颜色合并按照个数dp, 设 \(dp[c1][c ...
- OpenHarmony社区运营报告(2023年5月)
本月快讯 ● 2023年6月11-13日,2023开放原子全球开源峰会即将在北京北人亦创国际会展中心盛大开幕.2023开放原子全球开源峰会上,OpenAtom OpenHarmony(以下简称&q ...
- 【直播回顾】OpenHarmony知识赋能五期第五课——多媒体子系统之视频解读
5月19日晚上19点,知识赋能第五期第五节课<OpenHarmony标准系统多媒体子系统之视频解读>,在OpenHarmony开发者成长计划社群内成功举行. 本期课程,由深开鸿资深技术专家 ...
- pprof - 在现网场景怎么用
如何使用 pprof 来定位现网 Golang 问题,已经是一名 Gopher 所需要掌握的必备技能了.我们在实际工作中也经常使用它来定位现网问题.网上有很多文章来描述 pprof 的使用,但是实际的 ...
- Redis 02 基础命令
数据库 Redis 默认有 16 个数据库. 默认使用的是第 0 个数据库. 不同数据库存不同的值. 切换数据库 select 127.0.0.1:6379> select 1 OK 127.0 ...
- HarmonyOS系统级推送服务,打造消息通知新体验
8月4日,第五届华为开发者大会 2023(HDC.Together)再次启航.在本次大会上,华为为广大用户带来了HarmonyOS 4全新升级的体验,同时,针对HarmonyOS应用的开发,此次也全面 ...
- Python操作临时文件---tempfile
# 使用标准库中 tempfile 下的 TemporaryFile,NamedTemporaryFile # TemporaryFile(mode='w+b', bufsize=1, suffix= ...
- VSCode如何通过Ctrl+P快速打开node_modules中的文件
背景 咱们新建一个NodeJS项目,必然会安装许多依赖包,因此经常需要查阅某些依赖包的源码文件.但是,由于node_modules目录包含的文件太多,出于性能考虑,在VSCode中默认情况下是禁止搜索 ...
- 深入解析C++的auto自动类型推导
关键字auto在C++98中的语义是定义一个自动生命周期的变量,但因为定义的变量默认就是自动变量,因此这个关键字几乎没有人使用.于是C++标准委员会在C++11标准中改变了auto关键字的语义,使它变 ...
- nginx重新整理——————nginx 模块[十]
前言 简单介绍一下nginx的模块. 正文 https://nginx.org/en/docs/ 这里面可以看到官方模块. 比如打开这个模块: https://nginx.org/en/docs/ht ...