续:C++ Iostreams 用法详解(一)整体把握

首先说我们最常用的两个全局对象cin和cout,以下摘自MSDN:

You can then extract values from cin or wcin to read the standard input. The rules for doing so are outlined in the description of the class basic_istream Class. You can also insert values to cout or wcout to write the standard output. The rules for doing so are outlined in the description of the class basic_ostream Class.

可以看出,其中cin是istream的对象,可以从标准输入中提取数据,而cout是ostream的对象,可以向标准输出中输出数据。

什么是标准输入和标准输出呢?可能对于我们这些90后来说不是那么容易理解的,毕竟这是字符界面的概念,而我们在开始接触计算机的时候就已经是普遍的windows图形界面的操作系统了。但是windows操作系统还是为我们提供了一个模拟dos这种字符界面的程序cmd,让我们大致对这个有一定的了解。而在Linux系统中我们更容易说清楚这个概念:在执行一个shell命令时,会默认打开三个标准文件,即标准输入文件(stdin),通常对应终端的键盘;标准输出文件(stdout)和标准错误输出文件(stderr),这两个文件都对应终端的屏幕。进程将从标准输入文件中得到输入数据,将正常输出数据输出到标准输出文件,而将错误信息送到标准错误文件中。

这样说比较了解了吧,因为我们在windows下面写一个win32 控制台应用程序的时候,其实我们的这个程序就是类似于Linux中执行在shell中的命令,所以这个程序在执行的时候当然可以带有参数(就是main函数的参数int argc和char* argv[]了),而且有标准输入缓冲区和标准输出缓冲区的概念了。只不过我们在windows下刚开始学习编程语言的时候,总是会用一些图形界面的IDE(例如VC++6.0就是我的启蒙IDE),所以对这个程序的运行机制并不是很清楚,只知道摁一下运行按键就自动完成了编译、连接、打开一个cmd并直接运行我们写的这个程序了。

有了标准输入和输出的概念(最好把他们像Linux里面一样看成是设备文件),接下来就要说一下这个cin和这个cout到底是怎么完成输入输出机制的了。首先来看一下下面这个例子:

#include <iostream>
#include <string>
using namespace std;
 
int main()
{
    int j = 0;
    while(++j>0)    for(int i=0;i>0;i++);
    string str;
    cin >> str;
    cout << str << endl;
    system("pause");
}

用嵌套的循环来做了一个延时,当我们的程序(win32 控制台应用程序)在正常运行的时候,我们在键盘上敲下五个字符"hello",这个时候屏幕上并不会显示任何东西,因为虽然我们的输入都保存到了输入缓冲区中,但是我们并没有把它显示到屏幕上来。当我们第一次调用cin>>str的时候,这时其实是调用了cin这个istream对象的>>运算符的方法,它首先让我们的进程从运行(running)状态转换到等待I/O(waiting)状态,然后将输入缓冲区中的内容都输出到屏幕上来,这个时候我们刚才在键盘上按的hello就都显示出来了,然后当我们继续在键盘上按五个字符"world"的时候,输入缓冲区继续吸收我们输入的字符,然后被cin对象显示到屏幕上来,直到我们在键盘上按回车键(正常情况下)时,这时输入缓冲区也同时吸收了一个换行字符'\n',这个时候输入缓冲区中就有11个字符"helloworld\n"了,然后cin>>str开始将输入缓冲区中的这11个字符全部抽取(extract)出来存到对象cin的streambuf中(后面会讲到,这其实就是存储的buffer,而cin对象拥有的其实是streambuf对象的指针)。到这一步,还没有跟我们的str对象有任何关系,cin对象只是从标准输入输出中提取出了数据而已(这时我们可以理解为输入缓冲区中已经空了)。
之后的工作才关系到str对象,cin对象会根据str的类型(string)去格式化stream中的内容,即将前10个字符"helloworld"存到str对象中去,同时从streambuf中将这10个字符和结束字符'\n'清除(这其实是通过移动get指针来实现的,后面会说到),然后这条语句cin<<str;终于执行结束了。如果我们的代码改成

char str[20];
cin >> str;

这时格式化工作就变为:前10个字符"helloworld"存到str对象中去,并将str[10]改为0作为字符串结束标志,前10个字符"helloworld"存到str对象中去,同时从streambuf中将这10个字符和结束字符'\n' “清除”。
这里需要说明的是,对于每次我们使用cin>>时,首先cin判断自己的streambuf是否为空,如果是空的话,就触发一次进程状态的转换,然后开始等待用户的输入等过程。但是如果streambuf不是空的,则会先尝试从streambuf中的数据中去格式化所需的数据。当然,这个格式化过程并不一定都是正确的,这个问题后面再论。
我们在使用cin来从标准输入缓冲区中得到字符串时,有时候使用cin >> str并不能解决问题,因为对于这样的操作,在最后解析streambuf中的数据的时候,它会以空格' '、制表符'\t'、换行符'\n'来作为格式化字符串的结束字符,也就是说比如上面的代码当我们输入"hello world\n"的时候,我们得到的字符串为"hello",因为在遇到空格的时候就已经结束了字符串,注意这时streambuf中还有剩下的数据"world\n",如果我们现在再次执行cin >> str则会以'\n'为结束字符,获取到字符串"world"。那如果我想一次性的获取字符串"hello world"要怎么做呢?
istream也提供了两个获取整行字符串的(其实就是以换行符'\n'作为格式化字符串的结束字符)成员函数,分别就是get和getline。关于这个两个函数的使用以及其各种重载的版本等等我在这里就不多说了,自己去查MSDN吧。我在这里只说一下这两个函数最大的区别,那就是get函数在从streanbuf中格式化数据的时候,虽然也是以'\n'作为结束符,但是并不会清除掉streambuf中的这个字符,也就是说当我输入字符串"hello world\n"的时候,get函数会正确的得到字符串"hello world",但是会将字符'\n'留在streambuf中,而getline函数将得到与get函数一样的结果,但是不会将字符'\n'留在streambuf中。这有什么区别呢?区别就比较大了,考虑下面的代码:
char str1[20],str2[20];
cin.get(str1,20);
cin.get(str2,20);

现在我输入字符串"hello world\n"('\n'就是回车键),成功的得到了字符串str1内容为"hello world",这时streambuf中还剩下'\n',继续进行cin.get(str2,20),由于streambuf是非空的,就会直接格式化出str2,于是我们就得到str2的内容为"",空的!但是如果我们上面使用的是getline函数,就会正常的让我们输入两个字符串了。
还有,istream还提供了成员函数ignore,可以使get指针跳过字符,具体去查MSDN吧。如果在上面的代码中两个get函数之间插入cin.ignore()代码也会正常的让我们输入两个字符串。
对于 cout标准输出过程,就跟上面的过程有点类似,可以从上面的例子中看到cin过程和标准输出过程是完全互不相关的。每次使用cout进行输出时,都会自动的调用flush(将streambuf中的数据显示到屏幕上),所以在这里了解flush并没有太大的意义,后面的文件操作部分也会讲到。而关于数据的格式化输出,在后面也会讲到,所以现在也就不说了。cout用起来还是比较简单的。
关于istream和ostream的更多成员函数大家可以去查MSDN了解。
没什么写博客的经验,所以可能写的比较啰嗦(我自己也感觉很啰嗦)。另外再强调我还是新手,有大神发现我有说错的请一定提出啊。欢迎交流,一起学习。

转载于:https://www.cnblogs.com/zorro-x/archive/2013/05/11/3072305.html

C++ Iostreams 用法详解(二)标准输入输出相关推荐

  1. 8.linux 重定向详解,标准输入输出,输入重定向,输出重定向

    文章目录 一.初识 1.标准输入输出设备 2. 文件描述符 3. 重定向 3. &(重点) 二.输入重定向 三.输出重定向 1. 描述符 2. 输出重定向的符号及作用 总结 友情链接 一.初识 ...

  2. java typedef的用法_Java 枚举用法详解(二)

    枚举可以添加方法 在概念章节提到了,枚举值默认为从0开始的有序数值 .那么问题来了:如何为枚举显示的赋值. Java 不允许使用 = 为枚举常量赋值 如果你接触过C/C++,你肯定会很自然的想到赋值符 ...

  3. PaddlePaddle基本用法详解(二)、PaddelPaddle训练水果分类模型

    PaddlePaddle基本用法详解(二).PaddelPaddle训练分类模型 1.基本用法 2.训练水果分类模型 1.基本用法 2.训练水果分类模型 1.数据集预处理与模型定义代码: import ...

  4. STL中map和string, vector 用法详解

    1. map 用法详解 std map是STL的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据处理能力,由于这个特性,它完成 ...

  5. Java IO用法详解

    一.java io 概述 1.1 相关概念 Java IO Java IO即Java 输入输出系统.不管我们编写何种应用,都难免和各种输入输出相关的媒介打交道,其实和媒介进行IO的过程是十分复杂的,这 ...

  6. Java 注解用法详解——@SuppressWarnings

    转自: https://www.cnblogs.com/fsjohnhuang/p/4040785.html Java魔法堂:注解用法详解--@SuppressWarnings 一.前言 编码时我们总 ...

  7. linux mount命令参数及用法详解

    linux mount命令参数及用法详解 非原创,主要来自 http://www.360doc.com/content/13/0608/14/12600778_291501907.shtml. htt ...

  8. Linux下的awk用法详解

    Linux下的awk用法详解 一.awk介绍 二.awk的语法 三.awk常见用法 四.awk其他用法 五.awk语言特性 一.awk介绍 1.AWK 是一种处理文本文件的语言,是一个强大的文本分析工 ...

  9. Python中第三方库Requests库的高级用法详解

    Python中第三方库Requests库的高级用法详解 虽然Python的标准库中urllib2模块已经包含了平常我们使用的大多数功能,但是它的API使用起来让人实在感觉不好.它已经不适合现在的时代, ...

  10. response.setHeader()的用法详解及实现文件下载过程中出现问题的分析

    response.setHeader()用法详解,转载记录: 1. HTTP消息头 (1)通用信息头 即能用于请求消息中,也能用于响应信息中,但与被传输的实体内容没有关系的信息头,如Data,Prag ...

最新文章

  1. Linux的secureCRT设置字体大小
  2. XML Parsing in a Producer-Consumer Model
  3. centos7 安装python3
  4. linux java -xms_java.lang.OutOfMemoryError及解决方法
  5. Vue之前端页面使用json编辑框
  6. JavaSE——面向对象进阶(封装、this、static、代码块、包、权限修饰符、main方法详解)
  7. linux 7 远程桌面xrdp,[转帖]CentOS7安装xrdp(windows远程桌面连接linux)
  8. CGAL4.4+VC2008编译
  9. 为什么numba不能提高背包功能的速度?
  10. [bigdata-093] drool 规则引擎安装和试用(不全)
  11. 管理信息系统期末复习
  12. ccy测试影响因子版270ms
  13. 转行软件测试两个多月,感觉很迷茫,下一步该如何提高自己?
  14. 利用clamav为程序添加查毒功能
  15. 接口设计需要考虑哪些方面
  16. DOS时代后,金山系再出神级办公软件,会像WPS一样普及
  17. Kubeadm搭建高可用K8S(四)Dashboard安装配置
  18. 让我摘下星星送给你_抖音想摘下星星给你是什么歌 星球坠落原唱是谁
  19. java中的依赖是啥意思_java – “ – ”(箭头)在gradle的依赖图中是什么意思?
  20. Veritas NetBackup8.1.1汉化

热门文章

  1. tomcat access log pattern
  2. oracle hint 谓词推进,SQL Hint都无法解救DB性能时,如何通过视图曲线救国?
  3. 【渝粤教育】电大中专电商运营实操 (13)作业 题库
  4. 数字图像处理(七) 图像分割
  5. 推荐系统000111
  6. Python实现人工神经网络逼近股票价格
  7. springmvc框架使用拦截器实现301永久重定向,其实用过滤器应该是更好
  8. 教你如何修改运行中的docker容器的端口映射
  9. ShopEx 中规格属性添加时,自己主动计算其相应的销售价格,同一时候注意模板中的变量间的计算...
  10. 算法笔记_083:蓝桥杯练习 合并石子(Java)