c++中的输入输出都是用“类”来进行,无论是 cin,和cout都是类的一个对象。
c++中负责IO的有3中类型
1: istream、ostream 从流读写数据(i表示in也就是读,o表示out也就是写),你可以认为流就是控制台输入输出的数据,cin和cout就分别是他们俩的对象。
2: ifstream、ofstream f 表示file,也就是从文件读写数据
3: istringstream, ostringstream 从string读写数据。
其中2,3是继承的1。那么有了这些类之后读写过程是怎样的呢?
我们以cin为例,首先你在控制台输入字符敲下回车键以后数据就到了到缓冲区,你可以认为cin与缓冲区之间已经建立好了一层通道可以直接读数据,所以我们直接用cin读数据就可以了是不是很简单。
那如何从文件读写数据?和cin一样,我们创建一个文件流对象,然后需要我们自己用open函数建立通道,然后就可以通过对象进行写读数据操作。第三种string也是一样的。
#include#include "my_lib.h" using namespace std; int main(){ string s; cin >>s; //[空格][空格]abc[空格]cd[回车] cout < > s;//和cin效果一样,只不过是从文件读数据 ofs << s; //程序开始之前 a.txt内容为 hello hi b.txt为空白文件 //程序结束之后 b.txt的内容变为了 hello }
分析上面的代码我们发现无论是ifs还是cin都只读取了一串字符,遇到空格就不读取了,而且一开始的自动忽略了,那剩下的内容呢?读写规则是怎样的,还有如果想读取一行又该如何解决?
cin cout 具体读写规则
首先cin是从标准输入(缓冲区)读数据的。当开始读数据时,如果一开始遇到的是分隔符比如tab 换行,空格等,它会自动忽略这些字符接着读,如果读入数据之后再遇到分隔符则本次读入结束(进入下一行代码),注意此时分隔符仍留在缓冲区未清理。举个栗子
#include#include "my_lib.h" using namespace std; int main(){ string s1,s2; int a1,a2; //用键盘敲下 [空格][空格]abc[空格]12[回车] cin >> s1;//首先忽略前两个空格,将abc读入了s1,然后遇到了空格表示本次读入结束,空格留在缓冲区 cin >> a1;//注意在开始这一句之前缓冲区里的数据为[空格]12[回车],然后忽略第一个空格将12读入a1,遇到换行符结束,换行符留在缓冲区 //假设这里我又用键盘敲下 def[空格]34[回车] cin >> s2;//注意!!在这句开始之前缓冲区里的数据不是def[空格]34[回车] 而是[回车]def[空格]34[回车],因为你上次键入的回车还留在缓冲区!!所以这一句是先忽略回车,再将def读入! cin >> a2;//忽略空格 将34读入遇到回车结束,回车留在缓冲区不处理! }
一定要弄懂对分隔符的处理方式,这很重要!!
cin.get()函数
cin 是istream类的一个对象,所以他有类成员函数也并不奇怪,常用的cin.get()方式如下
int get(); istream& get(char& var); istream& get( char* s, streamsize n ); istream& get( char* s, streamsize n, char delim);
先看前两个,读取一个字符,
需要注意的是,和cin不一样,如果一开始有分隔符这种操作是会读取分隔符然后结束的,举个栗子。
#include#include "my_lib.h" using namespace std; int main(){ char c; char d; //敲入 a[回车] cin.get(c);//读入a cin.get(d);//读入回车,此时d的ascii码为10,也就是'n'回车字符! }
再看第三个读取字符串操作,注意,这里参数为char* 不能为string。s是你要输入的char数组的地址,streamsize是扫描的字符数
get函数会从缓冲区第一个字符开始扫描直到遇到’n’换行符,或者扫描的字符大于等于streamsize了(也就是最多扫描streamsize-1个),然后将扫描的字符串加上’ ’送入数组(没错,最后会自动给他加一个结束符标识结束)。举个栗子
#include#include "my_lib.h" using namespace std; int main(){ char s[7] = "hellh";// 初始化字符串,不够的会自动补' ',s字符串为 h e l l h ' ' ' ' //键入[空格]ab[回车] cin.get(s,5);//读取空格加ab,遇到回车结束,将回车留在缓冲区此时 s为 [空格] a b ' ' h ' ' ' ' char c; cin.get(c);//读取缓冲区的回车 }
第四个get()函数把换行符变为了特殊的字符,遇到换行符不再结束,而是遇到该字符结束,不再细讲。
需要注意的是,如果一开始就是一个回车,这时候最好不要用第三四种读入(没什么意义),而且好像之后cin就不起作用了。
cin.getline()函数
istream& getline(char* s, streamsize count); //默认以换行符结束 istream& getline(char* s, streamsize count, char delim);
cin.getline()和第三四种cin.get不同的是,遇到换行符会结束,并清空缓冲区中的换行符
但如果一开始就是一个回车,这种方法不会出错,他会将一个’ ’写入到s中,然后清空这个回车。
getline()函数
cin.get()或者cin.getline()向char*中输入毕竟不太方便,所以c++定义了一个全局函数getline(),可以直接向string中输入.
istream& getline (istream& is, string& str); // 默认以换行符n分隔行 istream& getline (istream& is, string& str, char delim);
这个没啥好说的,遇到换行符或者你自定义的delim结束,会自动加上一个’ ’写入string, 然后把换行符清空。
但如果一开始就是一个回车,这种方法不会出错,他会将一个’ ’写入到s中,然后清空这个回车。
因为可以向string输入用法也简单,所以一般都是用这种吧,而且这种还可以和stringstream搭配(刷题必备)。
istringstream ostringtream
和上面的两种一样,只不过是绑定到string上。
#include#include "my_lib.h" using namespace std; int main(){ string s1="ffrewe"; string s2; istringstream ssin(s1);//s1的内容已经转换成流写入ssin啦 ostringstream ssout; ssout << "fefre fr";//向ssout写入string类型的东西 s2 = ssout.str();//将ssout的内容输出到s2. cout << s2; }
总结
1、首先要搞清楚各个函数是如何处理分隔符的!!
2、比如刷题的时候,如果告诉你数据的行数n, 每行数据量m,那就直接建一个vectorvector> 然后用for(int i;…) cin>> 就可以了。
#include#include "my_lib.h" using namespace std; //题目:标准输入如下:首先数字n表示有n行,然后是数据m表示每行有m个数据, //请你将这n*m个数据存储到vector中并输出 int main(){ int n; int m; cin >>n>>m; vector > v(n,vector (m)); for(int i=0;i > v[i][j]; } } }
3、如果只告诉你数据的行数,但不告诉你每行数据有多少呢?
#include#include "my_lib.h" using namespace std; //题目:标准输入如下:首先数字n表示有n行,然后是n行数字每行以换行符结束,请你将这n行数字存储到vector中 int main(){ int n ; cin>> n; getchar();//请分析getchar的作用,如果没有会怎样 vector > v(n); for(int i=0;i > a){ v[i].emplace_back(a); } } printMatrix(v); }
需要注意之所以可以用while(ssin>>a)是因为把temp转化为ssin的过程中,它自动在temp的后面加了一个结束符,当ssin遇到结束符时会返回一个非1的值,此时while结束了。你直接用while(cin >> a)读取控制台的内容,那永远不会结束,因为cin >> 遇到换行符会自动过滤掉但并不会结束,就一直阻塞在那了!!所以我们一般看不到也不知道行数也不知道个数的控制台输入,那时候可能要判断缓冲区还有没有数据。。以后在写吧
还有就是各种出错码改状态之类的,有空再写吧。
全文完。。。。如果有用点个赞吧。



