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 ...
随机推荐
- LeetCode - 231. Power of Two - 判断一个数是否2的n次幂 - 位运算应用实例 - ( C++ )
1.题目:原题链接 Given an integer, write a function to determine if it is a power of two. 给定一个整数,判断该整数是否是2的 ...
- CentOS6 安装VNCserver
1.下载vncserver yum install tigervnc tigervnc-server -y 2.配置 vncserver vi /etc/sysconfig/vncserver 在文件 ...
- OJ错误命令解释
①Presentation Error (PE) : 虽然您的程序貌似输出了正确的结果,但是这个结果的格式有点问题. 请检查程序的输出是否多了或者少了空格(' ').制表符('\t')或者换行符('\ ...
- Java学习个人备忘录之线程间的通信
线程间通讯多个线程在处理同一资源,但是任务却不同. class Resource { String name; String sex; } //输入 class Input implements Ru ...
- LintCode-68.二叉树的后序遍历
二叉树的后序遍历 给出一棵二叉树,返回其节点值的后序遍历. 样例 给出一棵二叉树 {1,#,2,3}, 返回 [3,2,1] 挑战 你能使用非递归实现么? 标签 递归 二叉树 二叉树遍历 code / ...
- linux shell学习(字符串操作)--01
http://blog.csdn.net/shuanghujushi/article/details/51298672 在bash shell的使用过程中,经常会遇到一些字符串string的操作,下面 ...
- Java设计
重构前 CustomDataChar | getConnection()findCustomers()createChar()displayChar() 重构后 CustomDataChar | da ...
- 【其他】VS提示不一致的行尾
应该是用不同的编辑器或平台编辑过同一个文件,比如Windows是\r\n,有的系统只有一个\n, 需要都统一,否则代码可能会堆成一堆.
- AC自动机裸题
HDU 2222 Keywords Search 模板题.对模式串建立AC自动机然后在trie树上找一遍目标串即可. # include <cstdio> # include <cs ...
- 【bzoj4491】我也不知道题目名字是什么 离线扫描线+线段树
题目描述 给定一个序列A[i],每次询问l,r,求[l,r]内最长子串,使得该子串为不上升子串或不下降子串 输入 第一行n,表示A数组有多少元素接下来一行为n个整数A[i]接下来一个整数Q,表示询问数 ...