cin.get()、流和缓冲区
大家好,这是我在CSDN的第一篇博客。我是一名学习GIS专业的大学生。我从小开始喜欢编程,可是到现在编程水平却长进不大,依然是菜鸟一个。究其原因,虽然这些年乱七八糟的东西学过不少,但是总的来说还是基础不够扎实。所以我从最近一段时间我便买了本C++ Primer Plus正式开始从零学习C++。我现在正准备出国留学平时主要时间用来学习英语,但每天还是会抽出40分钟看C++,看完一章便把书后的编程题挨个写一遍。现在我已经看到了第8章,也就是说与C有关的基础知识看完了。有一些心得体会想在这里整理一下,顺便与一起初学C++的同学们分享。这些体验不仅仅来自我自己的感悟,同样来自于CSDN论坛上各路高人的解答,在此要谢谢各位。
虽然说C++ Primer Plus的前7章差不多都是重述C语言的知识,但这并不代表你懂得点C语言就可以忽略这些内容,直接从OOP开始学!和输入和输出有关的缓冲区操作便是一个非常重要但又特别容易被我们这些C++菜鸟所忽视的内容,我在写C++ Primer Plus编程练习时出现的绝大多数bug都和它有关。
对于我这样从BASIC学到VB再学到C的人来说,想弄明白缓冲区是个什么东西还真不是一时半会的事,因为在BASIC和C中根本没有缓冲区的概念。好,现在先看一个小程序。
- #include<iostream>
- using namespace std ;
- int main()
- {
- char ch ;
- cin.get(ch);
- while (ch!='/n')
- {
- cout<<ch ;
- cin.get(ch);
- }
- return 0;
- }
在运行这个程序时,如果你输入123456789,回车后他将回显123456789。一开始我对此很费解,因为这种运行结果好像是输入一个字符串接着再输出它,但事实上并没用到字符串,这里便牵涉到了流的概念:传统的程序是输入设备给一个信息(这里理解为从键盘输入一个字符),程序就接收一个,而C++颠覆了这个概念,它使用了流和缓冲区。打个比方,程序是一个脸盆(囧~~~)用来接水的,水在这里比喻数据,传统的程序是直接往脸盆里倒水。而C++程序则在脸盆上加一个漏斗,漏斗上还有个塞子,水不是直接进脸盆而是先进漏斗,而且在进水时塞子是塞住的,当数据输入完毕时(回车时),塞子打开,数据才开始进入程序。从这个程序看,当运行到第一个cin.get时,因为缓冲区(漏斗)是空的,程序便停下来等待数据,输入一串字符并回车,注意这些字符没进入程序而是进入了缓冲区。然而第一个cin . get 只接收缓冲区前端的第一个字符,进入while循环后一切就变得很神奇。while循环中也有cin . get ,不过程序在这里却不会停了,因为缓冲区在这时候有数据,cin . get 便再从缓冲区读一个字符,这使得while循环在一瞬间就运行完成了,造成好像是在处理字符串的错觉。当然,这个程序演示的是把漏斗的水连续放空的情况,当然你也可以把塞子中途塞住。再看下面一个程序,这个程序更有助于理解缓冲区的工作原理:
- #include<iostream>
- using namespace std ;
- int main ()
- {
- char ch ;
- cin.get (ch);
- while (ch!='5')
- {
- cout<<ch ;
- cin.get(ch);
- }
- cout<<endl<<"下面还有哦"<<endl;
- while(ch!='/n')
- {
- cout<<ch;
- cin.get(ch);
- }
- return 0;
- }
程序设定在输入123456789后回显时接收到5的时候停止从缓冲区接收数据,输出一行中文字再接着回显,相当于在接收到5的时候把塞子塞住,打印一行字后再接着放。注意在中文字之前这个程序只回显1234,5在中文字后出现,各位可以想想为什么。
当然,缓冲区里有时候也会出现垃圾,设想一下下面一种情况。
- #include<iostream>
- using namespace std;
- int main()
- {
- char a[100];
- cin.getline(a,100,'@');
- cout<<a<<endl;
- char b[100];
- cin.getline(b,100,'@');
- cout<<b<<endl;
- return 0;
- }
这个程序先输入一个字符串,以@作结束符,回显这个字符串,再反复一次。这样运行程序显然没有问题:
I'm a C++ beginner.@
I'm a C++ beginner.
You're a VB beginner.@
You're a VB beginner.
可是这并不能说明程序就没有问题,一个完美程序不仅仅要在正确输入时有正确结果,更要在错误输入时不至于崩溃。这就是一个程序的坚固性,个人作为一个初学者认为初学者学习编程不能盲目图快图新,即便是再简单的程序也要具有优秀程序的完美特性。下面想象一下有些人天生比较猥琐故意想找你程序的茬,他可能会这么运行:
I'm a professional C++ coder.@HA HA HA!
I'm a professional C++ coder.
You're a C++ noob.@
HA HA HA!
You're a C++ noob.
这下子出问题了,第一个字符串中@后的内容明明不要了,却怎么还在第二个字符串回显时出现了,给人感觉极其诡异!实际上原因还是出在缓冲区上面,当getline方法扫描到@这个结束符时输入便结束了,剩下的内容(注意还包括你敲的那个回车)便留在了缓冲区中,第二个getline方法再执行时便先把刚才留在缓冲区中的那个HAHAHA一股脑放进了字符串b中,由于最后一个字符是回车不是@,所以输入并没有结束而缓冲区里却没东西了,于是程序出现了光标等待输入,给人一种从零开始的假象,实际上字符串b这时候已经有数据了,最后出现那种结果也不足为奇了。
想解决这个问题只有在输入字符串b之前把缓冲区清空,这里有一种比较容易想到的方式:
- #include<iostream>
- using namespace std;
- int main()
- {
- char a[100];
- cin.getline(a,100,'@');
- cout<<a;
- char waste;
- cin.get(waste);
- while(waste!='/n')
- cin.get(waste);
- char b[100];
- cin.getline(b,100,'@');
- cout<<b;
- return 0;
- }
这种方法就是把缓冲区里面不要的数据挨个扔掉,直到检测到回车符为止。可这种方法第一局限性很大,只能适应这个程序,第二就是时间复杂度高,遇到要抛弃大量数据的情况时耗时巨大。有没有一股脑把这些没用的数据倒掉的方法呢?有!请看下面:
- #include<iostream>
- using namespace std;
- int main()
- {
- char a[100];
- cin.getline(a,100,'@');
- cout<<a;
- cin.sync();
- char b[100];
- cin.getline(b,100,'@');
- cout<<b;
- return 0 ;
- }
这是我在CSDN里学到的方法,用cin的sync方法可以一下子把缓冲区清空,以上两个程序无论怎么输入便都可以正常执行了。
看来就算是C++里面向过程的东西都有这么多玄机在里面,所以说初学C++真的不要急于去研究OOP,基础打牢同样重要。鄙人也是个菜鸟,若有什么不对的地方请高手们指正啊!
cin.get()、流和缓冲区的更多相关文章
- getchar() 、 scanf() 、流与缓冲区
C中的缓冲区一直是debug的重灾区,今天在写一个命令行界面的时候又遇到了这个问题,所以来总结一波. 两函数的不同之处 scanf() 会把 stdinBuff 中的特定格式数据取出,非特定格式数据则 ...
- JAVA之旅(二十五)——文件复制,字符流的缓冲区,BufferedWriter,BufferedReader,通过缓冲区复制文件,readLine工作原理,自定义readLine
JAVA之旅(二十五)--文件复制,字符流的缓冲区,BufferedWriter,BufferedReader,通过缓冲区复制文件,readLine工作原理,自定义readLine 我们继续IO上个篇 ...
- Java精选笔记_IO流(字符输入输出流、字符文件输入输出流、字符流的缓冲区)
字符流 Reader是字符输入流的基类,用于从某个源设备读取字符 Writer是字符输出流,用于向某个目标设备写入字符 字符流操作文件 字符输入流FileReader,通过此流可以从关联的文件中读取一 ...
- IO 流之字符流的缓冲区
缓冲区的出现提高了对数据的读写效率 对应类: BufferedWriter BufferedReader 缓冲区需要结合流才可以使用, 对流的功能进行了增强, 即对流的操作起到装饰作用 使用缓冲区实现 ...
- DirectSound学习(二)--流式缓冲区
使用流式缓冲方式播放波形音频文件比较复杂,主要原因是在只有一个缓冲区提供给用户的前提下,这个缓冲区在提供给声卡播放数据的同是还需要用户不断的定时向其中写入数据.要注意从缓冲区这时是一个环形缓冲区,声音 ...
- node学习笔记(二)流和缓冲区
内容 视频 第四章内容 菜鸟教程服务器 //复制文件 function de(x) { console.log(x); } var fs=require('fs'); fs.mkdir('stuff' ...
- linux下清空c++ cin无效流的方式
cin.clear(); cin.ignore(10000,'\n');//这里面的参数很重要
- cin关闭流同步加速
习惯了用cin 很多人会说cin的速度比scanf慢很多, 其实不然. cin慢的原因主要在于默认cin与stdin总是保持同步, 这一步是消耗时间大户. 只需要加上std::iOS::sync_wi ...
- 黑马程序员——JAVA基础之IO流缓冲区,转换流,字节流
------- android培训.java培训.期待与您交流! ---------- 字符流的缓冲区 缓冲区的出现提高了对数据的读写效率. 对应类 • BufferedWriter ...
随机推荐
- Twaver的mono-desiner导出的json文件解析
以画的交换机为例,其他大概都差不多. 利用Twaver做出交换机模型如图1所示,其中,每一个端口都是一个单独的对象.具体Twaver操作流程参见网址:http://twaver.servasoft.c ...
- LintCode-174.删除链表中倒数第n个节点
删除链表中倒数第n个节点 给定一个链表,删除链表中倒数第n个节点,返回链表的头节点. 注意事项 链表中的节点个数大于等于n 样例 给出链表 1->2->3->4->5-> ...
- TCP系列27—窗口管理&流控—1、概述
在前面的内容中我们依次介绍了TCP的连接建立和终止过程和TCP的各种重传方式.接着我们在这部分首先关注交互式应用TCP连接相关内容如延迟ACK.Nagle算法.Cork算法等,接着我们引入流控机制(f ...
- 原生js移动端字体自适应方案
自从进入新公司之后,就一直采用800的方案,也就是判断屏幕尺寸,大于800px是一种html字体处理方案,另一种方案是小于800px的html字体处理方案, 代码如下: (function(doc, ...
- 关于已部署的WCF服务升级的问题
在日常的开发过程中,我们会经常迭代发布不同的版本,所以WCF服务的接口也会经常处于变动的状态,比如在传递实体类中新加一个字段.修改参数名称等等关于服务升级的问题.但是我们不可能让已发布的版本重新引用新 ...
- 操作 使用XML的方法
XmlHelper是一个工具类 public static class XMLHelper { /// <summary> /// XML的编码方式,默认是UTF-8 /// </s ...
- 【题解】51nod 1672区间交
二分答案 + two - pointer + 树状数组大法好ヽ(゚∀゚)メ(゚∀゚)ノ 我们可以直接二分一个答案,然后检验 是否存在一个值大于等于这个二分的答案的,且覆盖次数大于等于 \(k\) 的区 ...
- 【刷题】BZOJ 2038 [2009国家集训队]小Z的袜子(hose)
Description 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿.终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命-- 具体来说,小Z把这N只 ...
- [HNOI2007][BZOJ1185] 最小矩形覆盖 [凸包+旋转卡壳]
题面 BZOJ题面 前置芝士 建议先学习向量相关的计算几何基础 计算几何基础戳这里 思路 用这道题学习一下凸包和旋转卡壳 首先是凸包部分 凸包 求凸包用的算法是graham算法 算法流程如下: 找到$ ...
- BZOJ2693:JZPTAP——题解
http://www.lydsy.com/JudgeOnline/problem.php?id=2693 Description Input 一个正整数T表示数据组数 接下来T行 每行两个正整数 ...