C++ Primer 笔记+习题解答(八)
2015-02-03 21:38
344 查看
今天是第八篇笔记,主要总结的内容是C++标准库中的第一部分之IO库。最近几天因为一些环境干扰,更新的速度着实变慢。其实对小白来说,学习过程中比较可怕的一件事就是信息负载,故今日贴在博文首页,警醒自己。大致估计下日程安排。从2.4号起到除夕2.18号,共计14天。C++ Primer一共十八章,算上附录是19个章节。预计大年初二左右结束这本书的学习。节奏应该是一天看书,一天写博文总结。进入正题。
若存在错误 请指正 谢谢
我们已经接触到IO设施:
相关头文件:
由于IO类型之间存在继承关系,所以把继承对象当作基类对象使用。
在使用对象的时候,最好检测下流的状态,比如我们常见的:
我们讲流(对象)作为条件使用,只能知晓其是否出错,但是一旦出错我们不知道具体错误的,这个时候就可以通过函数检测。
其中注意到一点,缓冲区的几个分类:
全缓冲/行缓冲/无缓冲。具体内容可以翻看我搬运的博文,而且他们总结的比我好多了。
相关函数:
参见8.1两次测试。
8.3
8.6 8.7 8.8
具体的答案就不写了,我写一下如何从命令行编译运行程序以及如何向命令行传入参数。我看的书都直接一笔带过,导致我根本不会从命令行编译程序。这个东西就是很基础的知识,但是写书的人都默认我们会了,所以正计算机三观太有必要了。
8.9
8.12
End
若存在错误 请指正 谢谢
0.引言:
1.C++ 不存在直接处理输入输出的机制,而是转交给标准库中的类来处理IO。C++的IO机制支持从各种设备读写数据。这个地方的设备要好好理解下。设备可以指的是控制台窗口,命名文件,内存IO。
2.IO类型定义了内置数据类型的读写操作,不然形如这样的语句:
<span style="font-size:18px;">int var=0; cin>>var; cout<<var;</span>我刚学C++时候就特别好奇为什么可以这个样子搞,当时眼界阅历有限,虽然翻了不少书,但是大多数教材都是闭口不提标准库,对我而言着实坑爹。
我们已经接触到IO设施:
<span style="font-size:18px;">cout / cin /cerr />> /<< /getline /iostream </span>
3.下面会介绍一些新知识。
目前我们使用的IO类型都是关联到控制台窗口的,所以你会在屏幕上看见输入输出。但是程序的需求绝不仅限于此。相关头文件:
<span style="font-size:18px;">iostream/ ostream /istream fstream / ofstream /ifstream sstream / istringstream /ostringstream</span>其中C++为了支持宽字符类型,又定义了对应的宽字符版本类型,比如你可能看见如下的:
<span style="font-size:18px;">wostream wcin wcout ...</span>无需奇怪,两个版本之前用法无差异。
由于IO类型之间存在继承关系,所以把继承对象当作基类对象使用。
1.IO对象无拷贝或赋值:
1.由于无法拷贝和赋值,因此不能将形参和返回类型设为流类型,而是要设置成引用类型。因为读写流会改变流的状态,所以IO对象绝不会是const的。
2.相关状态量和函数:
<span style="font-size:18px;color:#330099;">iostate/goodbit/failbit/eofbit/badbit 上面的量是一些状态量,其iostate总合。 相关函数: eof() /fail()/good()/bad()/clear()/clear(flags)/setstate(flags)/rdstate()</span>具体的函数意思翻书或者谷歌就知晓了。
在使用对象的时候,最好检测下流的状态,比如我们常见的:
<span style="font-size:18px;color:#330099;">while(cin>>word)</span>我们已经学过运算符了,>>运算符返回的cin对象,所以实际检测的是对象的状态。
我们讲流(对象)作为条件使用,只能知晓其是否出错,但是一旦出错我们不知道具体错误的,这个时候就可以通过函数检测。
<span style="font-size:18px;color:#330099;">不可恢复的错误:badbit 被置位。 可修复的错误:failbit 被置位。 </span>当遇到文件结束符的时候,failbit和eofbit会被置位。一旦eofbit/failbit/badbit 任何一个被置位了,检测流状态得到布尔值是false。
3.缓冲相关:
每个流都管理一个缓冲区,用了保存数据。如下的行为会导致缓冲刷新:1.程序正常结束
2.缓冲区满。
3.输出控制符,如endl/ends/flush等。
4.在每个输出操作之后用unitbuf设置流内部状态。
5.流之间的相互关联。
相关解释:1.刷新输出缓冲区:
<span style="font-size:18px;color:#330099;">cout<<endl; 刷新缓冲并且换行。 cout<flush; 刷新缓冲。 cout<<ends; 附加一个空字符然后刷新缓冲区。</span>
2.unitbuf操纵符:
每次输出操作之后都会刷新缓冲区,行为是类似flush,不会有附加内容。一般来说unitbuf同cerr关系比较近,所以cerr是立即输出不缓冲的。5e<span style="font-size:18px;color:#330099;">cout<<unitbuf; //每次输出后都会刷新缓冲。 恢复正常缓冲刷新机制: cout<<nonunitbuf;</span>
3.缓冲去的一些补充知识,我就做个搬运工了哈。
缓冲去相关知识链接其中注意到一点,缓冲区的几个分类:
全缓冲/行缓冲/无缓冲。具体内容可以翻看我搬运的博文,而且他们总结的比我好多了。
4.关联输入流和输出流:
执行读取操作会导致输入缓冲区被刷新,也就是cin会刷新cout.相关函数:
1.无形参tie函数:返回指向调用函数对象所关联对象的指针,如调用函数的对象不不存在关联,那么返回的是一个空指针。
<span style="font-size:18px;color:#330099;">cin.tie();</span>
<span style="font-size:18px;color:#330099;">正常情况下,cin和cout关联,所以会返回一个指向cout的指针。</span>
2.有参数tie函数:将调用的对象同参数的对象关联起来。
<span style="font-size:18px;color:#330099;">cin.tie(&cerr);</span>
<span style="font-size:18px;color:#330099;">将cin关联到cerr.不被推荐的做法,因为cin应该同cout关联。</span>
tips:关联之间存在一种类似函数的关系,可以多对一,不可以一对多。意思就是多个对象可以关联到同一个ostream对象,但是一个对象不能被关联到多个ostream对象。
2.文件输入输出:
由于继承关系的存在,前面介绍的一些状态量和函数都是可以继续使用的,补充一下新增的函数:<span style="font-size:18px;">open/close/is_open</span>
<span style="font-size:18px;color:#330099;">三个函数是新增的,具体含义就不写了。</span>
1.ifstream in(file) file是文件名,可以是string 字符串或者c风格字符串。file是c风格字符串时记得一定要以空字符结尾。
2.可以先定义一个对象,然后调用open函数同具体文件绑定起来。如果open失败,failbit会被置位,尽量设置检测措施。
3.当一个对象被销毁时,会自动调用其close函数,斩断之间的关联。
4.文件模式:
in/out/app/ate/trunc/binary
5.以写模式打开的文件会丢失已有的数据:
解决措施是以app或着in模式打开文件。
ofstream out(file)ofstream out(file,ofstream::out)//丢失数据ofstream out(file,ofstream::out|ofstream::app)
3.string 流:
三个头文件:
<span style="font-size:18px;">istringstream/ostingstream/stringstream</span>
新增操作:
<span style="font-size:18px;">strm.str()//返回strm绑定的字符串拷贝。 strm.str(s)//把s拷贝到stream中。</span>
4.总结:
iostream 处理控制台IO;
fstream 处理命名文件IO;
sstream 处理string IO .
5.习题解答:
8.1<span style="font-size:18px;">#include <iostream> 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; }</span>8.2
参见8.1两次测试。
8.3
<span style="font-size:18px;">遇到错误的输入,比如i是int型的,你输入一个字符,那么流的状态就失效。 或者当你键入文件结束标识的时候,流的状态也会失效。 流的状态为假后,循环就会终止。一般来说eofbit /badbit/failbit 三者任何一个被置位都会导致循环结束。 </span>8.4
<span style="font-size:18px;">#include <iostream> #include <fstream> #include <vector> #include <string> using namespace std; int main(){ ofstream out; out.open("test.txt"); out << "hello world !!!"<<endl; out << "You are so beautiful " << endl; out.close(); ifstream in("test.txt"); string word; vector<string> svec; while (!in.eof()){ getline(in, word); svec.push_back(word); } for (auto x : svec) cout << x << " "; cout << endl; system("pause"); return 0; }</span>8.5
<span style="font-size:18px;">#include <iostream> #include <fstream> #include <vector> #include <string> using namespace std; int main(){ ofstream out; out.open("test.txt"); out << "hello world !!!"<<endl; out << "You are so beautiful " << endl; out.close(); ifstream in("test.txt"); string word; vector<string> 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; }</span>
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 <iostream> #include <string> #include<sstream> 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 <iostream> #include <fstream> #include <sstream> #include <vector> 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<string> 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 <iostream> #include <fstream> #include <sstream> #include <vector> 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<string> 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<stirng>可以顺利地被合成的默认构造函数初始化,无须多此一举。8.13
#include <iostream> #include <vector> #include <string> #include <sstream> #include <fstream> using namespace std; struct PersonInfo{ string name; vector<string> phone; }; //定义的结构体用了保存员工信息。 int main(){ string line, word; vector<PersonInfo> 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.14
避免了拷贝同时也防止了修改。
后记:
昨天晚上本打算一口气写玩的,但是等到写的时候突然泄气了,一股自卑感油然而生,心里总是想着你写不出来的,放弃吧。所以当时我选择了休息,第二天继续写,果然今天的状态好了很多。End
相关文章推荐
- C++ Primer 笔记+习题解答(十一)
- C++ Primer 笔记+习题解答(十)
- C++ Primer 笔记+习题解答(七)
- C++ Primer 笔记+习题解答(二)
- C++ Primer 笔记+习题解答(九)
- C++ Primer 笔记+习题解答(四)
- C++ Primer 笔记+习题解答(一)
- C++ Primer 笔记+习题解答(五)
- C++ Primer 笔记+习题解答(三)
- C++ Primer 笔记+习题解答(六)
- Introduction to Algorithms 算法导论 第1章 基础知识 学习笔记及习题解答
- C++ primer习题笔记第4章
- C++ Primer(第五版)读书笔记 & 习题解答 --- Chapter 2
- C++ primer习题笔记第7~9章
- C++ primer 习题笔记第5~6章
- 《算法导论》习题解答搬运&&学习笔记 索引目录
- Introduction to Algorithms 算法导论 第3章 函数的增长 学习笔记及习题解答
- C++ Primer(第五版)读书笔记 & 习题解答 --- Chapter 1
- DirectX 11游戏编程学习笔记之8: 第6章Drawing in Direct3D(在Direct3D中绘制)(习题解答)
- C++ primer 习题笔记第13~15章