当字符遇上 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);

运行结果如下:

第二次输出为什么会出现异常情况呢 ?

这里有两个问题

  1. 为什么出现了 请再次输入ch1的值:请再次输入ch2的值:的情况,按照原本的预测请应该是先出现请再次输入ch1的值:,键盘输入了一个字符之后再出现请再次输入ch2的值:,键盘再输入一个字符
  2. 为什么第二次输入ch1,的值后,直接就输出了ch1 和ch2 ,而且 ch1 = '\n', ch2 = 'C'?

第一个问题

​ 首先需要知道CPU 的工作原理

由于输入设备和输出设备对于数据的读写速度比较慢,CPU为了降低输入输出次数,提高运行效率,避免长时间的等待,所以内核就在内存中提供了一块空间作为缓冲区,( 缓冲区也可以称为缓存(Cache),是属于内存空间的一部分。)

每当使用读操作函数,试图将数据读取出来时,数据都会流过标准*输入缓冲区*,然后再在适当的时刻冲洗(或称刷新,flush)到内核缓冲区,最后才真正得到数据。

所以CPU 并不是没每时每刻都在读取数据,而是在满足刷新条件时才会从出入缓冲区读取数据。刷新条件按形式分为三种:全缓冲、行缓冲、无缓冲。

全缓冲:指的是当缓冲区被填满就立即把数据冲刷到文件、或者在关闭文件、读取文件内容以及修改缓冲区类型时也会立即把数据冲刷到文件,一般读写文件的时候会采用

无缓冲:指的是没有缓冲区,直接输出,一般linux系统的标准出错stderr就是采用无缓冲,这样可以把错误信息直接输出。

行缓冲:指的是当缓冲区被填满(一般缓冲区为4KB,就是4096字节)或者缓冲区中遇到换行符’\n’时,或者在关闭文件、读取文件内容以及修改缓冲区类型时也会立即把数据冲刷到文件中,一般操作IO设备时会采用,比如printf函数就是采用行缓冲。

知道了CPU 工作原理之后,我们就知道了printf() 函数的刷新条件有四个:

  1. 程序结束;
  2. 遇到换行 ‘\n’;
  3. 缓冲区满;
  4. 利用函数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() 要当心的更多相关文章

  1. 前端遇上Go: 静态资源增量更新的新实践

    前端遇上Go: 静态资源增量更新的新实践https://mp.weixin.qq.com/s/hCqQW1F8FngPPGZAisAWUg 前端遇上Go: 静态资源增量更新的新实践 原创: 洋河 美团 ...

  2. DP在字符匹配上的实现

    在此保存下近段时间做的DP在字符匹配上的实现的题目 对于不同的字符串来说,2者只能不断将下标往后推移来实现匹配从而得到的最大匹配数 如 abcd 和 dcba 这个最大匹配数只能为1,因为两个d匹配后 ...

  3. html实体编码遇上js代码

    单双引号 在js代码中 在js中单.双引号引起来的是字符串,如果我们要在字符串中使用单.双引号,需要反斜杠进行转义 let str='user\'s name'; // or let str=&quo ...

  4. MVC遇上bootstrap后的ajax表单模型验证

    MVC遇上bootstrap后的ajax表单验证 使用bootstrap后他由他自带的样式has-error,想要使用它就会比较麻烦,往常使用jqueyr.validate的话只有使用他自己的样式了, ...

  5. 敏捷遇上UML-需求分析及软件设计最佳实践(郑州站 2014-6-7)

      邀请函: 尊敬的阁下:我们将在郑州为您奉献高端知识大餐,当敏捷遇上UML,会发生怎样的化学作用呢?首席专家张老师将会为您分享需求分析及软件设计方面的最佳实践,帮助您掌握敏捷.UML及两者相结合的实 ...

  6. 敏捷遇上UML—软创基地马年大会(广州站 2014-4-19)

        我们将在广州为您奉献高端知识大餐,当敏捷遇上UML,会发生怎样的化学作用呢?首席专家张老师将会为您分享需求分析及软件设计方面的最佳实践,帮助您掌握敏捷.UML及两者相结合的实战技巧. 时间:2 ...

  7. 敏捷遇上UML——软创基地马年大会(深圳站 2014-3-15)

    邀请函: 尊敬的阁下: 我们将在深圳为您奉献高端知识大餐,当敏捷遇上UML,会发生怎样的化学作用呢?首席专家张老师将会为您分享需求分析及软件设计方面的最佳实践,帮助您掌握敏捷.UML及两者相结合的实战 ...

  8. 初识genymotion安装遇上的VirtualBox问题

    想必做过Android开发的都讨厌那慢如蜗牛的 eclipse原生Android模拟器吧! 光是启动这个模拟器都得花上两三分钟,慢慢的用起来手机来调试,但那毕竟不是长久之计,也确实不方便,后来知道了g ...

  9. SQL SERVER 2008 R2 SP1更新时,遇上共享功能更新失败解决方案

    SQL SERVER 2008 R2 SP1更新时,遇上共享功能更新失败的问题,可作如下尝试: 更新失败后,在windows的[事件查看器→应用程序]中找到来源为MsiInstaller,事件ID为1 ...

  10. 当创业遇上O2O,新一批死亡名单,看完震惊了!

    当创业遇上O2O,故事就开始了,总投入1.6亿.半年开7家便利店.会员猛增至10万……2015半年过去后,很多故事在后面变成了一场创业“事故”,是模式错误还是烧钱过度?这些项目的失败能给国内创业者带来 ...

随机推荐

  1. #线性dp,排列组合#洛谷 2476 [SCOI2008]着色方案

    题目 分析(弱化版) 最暴力的想法就是直接维护每种颜色的个数dp, 弱化版有一个很突出的地方就是 \(c_i\leq 5\), 也就是说可以将相同个数的颜色合并按照个数dp, 设 \(dp[c1][c ...

  2. OpenHarmony社区运营报告(2023年5月)

      本月快讯 ● 2023年6月11-13日,2023开放原子全球开源峰会即将在北京北人亦创国际会展中心盛大开幕.2023开放原子全球开源峰会上,OpenAtom OpenHarmony(以下简称&q ...

  3. 【直播回顾】OpenHarmony知识赋能五期第五课——多媒体子系统之视频解读

    5月19日晚上19点,知识赋能第五期第五节课<OpenHarmony标准系统多媒体子系统之视频解读>,在OpenHarmony开发者成长计划社群内成功举行. 本期课程,由深开鸿资深技术专家 ...

  4. pprof - 在现网场景怎么用

    如何使用 pprof 来定位现网 Golang 问题,已经是一名 Gopher 所需要掌握的必备技能了.我们在实际工作中也经常使用它来定位现网问题.网上有很多文章来描述 pprof 的使用,但是实际的 ...

  5. Redis 02 基础命令

    数据库 Redis 默认有 16 个数据库. 默认使用的是第 0 个数据库. 不同数据库存不同的值. 切换数据库 select 127.0.0.1:6379> select 1 OK 127.0 ...

  6. HarmonyOS系统级推送服务,打造消息通知新体验

    8月4日,第五届华为开发者大会 2023(HDC.Together)再次启航.在本次大会上,华为为广大用户带来了HarmonyOS 4全新升级的体验,同时,针对HarmonyOS应用的开发,此次也全面 ...

  7. Python操作临时文件---tempfile

    # 使用标准库中 tempfile 下的 TemporaryFile,NamedTemporaryFile # TemporaryFile(mode='w+b', bufsize=1, suffix= ...

  8. VSCode如何通过Ctrl+P快速打开node_modules中的文件

    背景 咱们新建一个NodeJS项目,必然会安装许多依赖包,因此经常需要查阅某些依赖包的源码文件.但是,由于node_modules目录包含的文件太多,出于性能考虑,在VSCode中默认情况下是禁止搜索 ...

  9. 深入解析C++的auto自动类型推导

    关键字auto在C++98中的语义是定义一个自动生命周期的变量,但因为定义的变量默认就是自动变量,因此这个关键字几乎没有人使用.于是C++标准委员会在C++11标准中改变了auto关键字的语义,使它变 ...

  10. nginx重新整理——————nginx 模块[十]

    前言 简单介绍一下nginx的模块. 正文 https://nginx.org/en/docs/ 这里面可以看到官方模块. 比如打开这个模块: https://nginx.org/en/docs/ht ...