今天是第八篇笔记,主要总结的内容是C++标准库中的第一部分之IO库。最近几天因为一些环境干扰,更新的速度着实变慢。其实对小白来说,学习过程中比较可怕的一件事就是信息负载,故今日贴在博文首页,警醒自己。大致估计下日程安排。从2.4号起到除夕2.18号,共计14天。C++ Primer一共十八章,算上附录是19个章节。预计大年初二左右结束这本书的学习。节奏应该是一天看书,一天写博文总结。进入正题。
若存在错误 请指正 谢谢
int var=0;
cin>>var;
cout<
我刚学C++时候就特别好奇为什么可以这个样子搞,当时眼界阅历有限,虽然翻了不少书,但是大多数教材都是闭口不提标准库,对我而言着实坑爹。cout / cin /cerr />> /<< /getline /iostream
目前我们使用的IO类型都是关联到控制台窗口的,所以你会在屏幕上看见输入输出。但是程序的需求绝不仅限于此。
相关头文件:
iostream/ ostream /istream
fstream / ofstream /ifstream
sstream / istringstream /ostringstream
其中C++为了支持宽字符类型,又定义了对应的宽字符版本类型,比如你可能看见如下的:
wostream
wcin
wcout
...
无需奇怪,两个版本之前用法无差异。iostate/goodbit/failbit/eofbit/badbit
上面的量是一些状态量,其iostate总合。
相关函数:
eof() /fail()/good()/bad()/clear()/clear(flags)/setstate(flags)/rdstate()
具体的函数意思翻书或者谷歌就知晓了。
在使用对象的时候,最好检测下流的状态,比如我们常见的:
while(cin>>word)
我们已经学过运算符了,>>运算符返回的cin对象,所以实际检测的是对象的状态。
我们讲流(对象)作为条件使用,只能知晓其是否出错,但是一旦出错我们不知道具体错误的,这个时候就可以通过函数检测。
不可恢复的错误:badbit 被置位。
可修复的错误:failbit 被置位。
当遇到文件结束符的时候,failbit和eofbit会被置位。一旦eofbit/failbit/badbit 任何一个被置位了,检测流状态得到布尔值是false。每个流都管理一个缓冲区,用了保存数据。如下的行为会导致缓冲刷新:
相关解释:
cout<
每次输出操作之后都会刷新缓冲区,行为是类似flush,不会有附加内容。一般来说unitbuf同cerr关系比较近,所以cerr是立即输出不缓冲的。5e
cout<
缓冲去相关知识链接
其中注意到一点,缓冲区的几个分类:
全缓冲/行缓冲/无缓冲。具体内容可以翻看我搬运的博文,而且他们总结的比我好多了。
执行读取操作会导致输入缓冲区被刷新,也就是cin会刷新cout.
相关函数:
cin.tie();
正常情况下,cin和cout关联,所以会返回一个指向cout的指针。
cin.tie(&cerr);
将cin关联到cerr.不被推荐的做法,因为cin应该同cout关联。
由于继承关系的存在,前面介绍的一些状态量和函数都是可以继续使用的,补充一下新增的函数:
open/close/is_open
三个函数是新增的,具体含义就不写了。
istringstream/ostingstream/stringstream
strm.str()//返回strm绑定的字符串拷贝。
strm.str(s)//把s拷贝到stream中。
8.1
#include
using namespace std;
istream& read(istream& cin){
int var = 0;
while (cin>>var){
cout << var << " ";
}
cout << "Test the stream before clearing " << endl;
if (cin)
cout << "The stream is valid " << endl;
else
cout << "The stream is not valid " << endl;
cout << "Test the stream after clearing " << endl;
cin.clear();
if (cin)
cout << "The stream is valid " << endl;
else
cout << "The stream is not valid " << endl;
return cin;
}
int main(){
read(cin);
system("pause");
return 0;
}
8.2 参见8.1两次测试。
8.3
遇到错误的输入,比如i是int型的,你输入一个字符,那么流的状态就失效。
或者当你键入文件结束标识的时候,流的状态也会失效。
流的状态为假后,循环就会终止。一般来说eofbit /badbit/failbit 三者任何一个被置位都会导致循环结束。
8.4
#include
#include
#include
#include
using namespace std;
int main(){
ofstream out;
out.open("test.txt");
out << "hello world !!!"< svec;
while (!in.eof()){
getline(in, word);
svec.push_back(word);
}
for (auto x : svec)
cout << x << " ";
cout << endl;
system("pause");
return 0;
}
8.5
#include
#include
#include
#include
using namespace std;
int main(){
ofstream out;
out.open("test.txt");
out << "hello world !!!"< svec;
while (!in.eof()){
//getline(in, word);
in >> word;//可以上下对比下。
svec.push_back(word);
}
for (auto x : svec)
cout << x;
cout << endl;
system("pause");
return 0;
}
8.6 8.7 8.8
具体的答案就不写了,我写一下如何从命令行编译运行程序以及如何向命令行传入参数。我看的书都直接一笔带过,导致我根本不会从命令行编译程序。这个东西就是很基础的知识,但是写书的人都默认我们会了,所以正计算机三观太有必要了。
如何从命令行编译运行程序以及向main函数传递参数。
这个方法适用于Visual Studio 2013,其余平台未测试过。
首先在vs 2013 中找到工具一栏,点开可以发现倒数几行有一个是 Visual Studion 命令提示。
点击它我们会发现弹出一个CMD命令行窗口。
接下来是先创建一个文件或者打开一个已经存在的文件。注意一定要加上notepad 关键字。格式是: notepad test.cpp
其中test可以换成自己想要建立的程序名。接着会弹出一个窗口,如果test未创建过,那么会提示你建立一个记事本文件。
你可以在记事本文件里面输入自己的源代码,然后点击文件菜单,保存,退出。
接下来就是编译阶段:
首先输入:
cl /EHsc test.cpp
然后你会在命令行窗口看见生成的可执行文件。
这个时候如果你想要向main函数传递参数,那么输入:
test 1 2 3 //后面的1 2 3 是我们传递给main的参数。你可以输出argc测试下。应该输出数字4.argv[0]指的是程序的名字。
如果你只是想单词的执行程序,那么直接输入:
test.exe 即可。
ps:像main函数传入参数的前提是你的main函数要有形参列表。
暂时介绍到这个地方,我也是初次接触。感兴趣的话可以直接
搜索关键字,已经有前辈们替我们总结过了。
8.9
#include
#include
#include
using namespace std;
istream& read(istream& cin){
string var;
while (cin>>var){
cout << var << " ";
}
cout << endl;
cout << "Test the stream before clearing " << endl;
if (cin)
cout << "The stream is valid " << endl;
else
cout << "The stream is not valid " << endl;
cout << "Test the stream after clearing " << endl;
cin.clear();
if (cin)
cout << "The stream is valid " << endl;
else
cout << "The stream is not valid " << endl;
return cin;
}
int main(){
string s = "Hello World ";
istringstream is(s);
read(is);
system("pause");
return 0;
}
//这个地方就体现了继承关系。我的形参是istream&类型,但是我传递的是一个isstringstream类型。
正好符号上面我们提到的子类当作父类用。
8.10
#include
#include
#include
#include
using namespace std;
int main(){
ofstream fout("temp.txt"); //打开一个文件,写点东西进去。
fout << "Hello Word " << endl;
fout << "You are so beautiful " << endl;
fout.close();//关闭这个文件。并且用读的方式再次打开,写的方式再次打开会丢失数据。
ifstream fin("temp.txt");
string line;
vector svec;
while (!fin.eof()){
getline(fin, line);
svec.push_back(line); //按行存进vector 中。
}
string word;
for (auto x : svec){
istringstream istirngin(x);
while (istirngin >> word)
cout << word<<" ";
cout << endl;
}
cout << endl;
system("pause");
return 0;
}
8.11
#include
#include
#include
#include
using namespace std;
int main(){
ofstream fout("temp.txt"); //打开一个文件,写点东西进去。
fout << "You are so beautiful " << endl;
fout << "Hello Word " << endl;
fout.close();//关闭这个文件。并且用读的方式再次打开,写的方式再次打开会丢失数据。
ifstream fin("temp.txt");
string line;
vector svec;
while (!fin.eof()){
getline(fin, line);
svec.push_back(line); //按行存进vector 中。
}
string word;
istringstream istirngin; //在体外定义对象。
for (auto x:svec){
istirngin.str(x); //体内采用自己函数进行绑定。
while (istirngin >> word)
cout << word;
cout << endl;
istirngin.clear(); //因为用while循环读取,所以最后eofbit被置位。故要清空流,我一开始没注意到这个问题。
}
cout << endl;
system("pause");
return 0;
}
体外的写法可以参考上面的。记得复位流的
状态。
8.12
因为string同vector可以顺利地被合成的默认构造函数初始化,无须多此一举。
8.13
#include
#include
#include
#include
#include
using namespace std;
struct PersonInfo{
string name;
vector phone;
};
//定义的结构体用了保存员工信息。
int main(){
string line, word;
vector People;
ofstream fout("information");//因为并没有写好的信息文件,所以只能在程序当成写。
fout << "John 1234567 2345678" << endl;
fout << "Max 6789090 12343890" << endl;
fout.close();
ifstream fin("information");
while (!fin.eof()){
getline(fin, line);
PersonInfo temp;
istringstream istringin(line);//同line 绑定到一起。
istringin >>temp.name;//保存姓名。
while (istringin>>word){
temp.phone.push_back(word);
}
People.push_back(temp);
}
system("pause");
return 0;
}
8.1
4
避免了拷贝同时也防止了修改。
昨天晚上本打算一口气写玩的,但是等到写的时候突然泄气了,一股自卑感油然而生,心里总是想着你写不出来的,放弃吧。所以当时我选择了休息,第二天继续写,果然今天的状态好了很多。