Skip to content

Commit dba45be

Browse files
committed
Updated to Chapter 13, Section 1
1 parent cb11de5 commit dba45be

File tree

13 files changed

+179
-74
lines changed

13 files changed

+179
-74
lines changed

.vscode/Test.cpp

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,17 @@
22
#include<exception>
33
#include<stdexcept>
44
#include<vector>
5-
class Complex {
6-
double real;
7-
double image;
8-
public:
9-
Complex(double r=0,double i=0):real{r},image{i}{}
10-
Complex operator+(const Complex &c)const{
11-
return Complex(real+c.real,image+c.image);
12-
}
13-
// friend Complex operator+(const Complex &c1, const Complex &c2){
14-
// return Complex(c1.real+c2.real,c1.image+c2.image);
15-
// }
16-
};
5+
#include<sstream>
6+
#include<stdio.h>
177
int main() {
18-
Complex a(1,2);
19-
2+a;
8+
std::istringstream sin {"25 1.3 Alan Turing"}; //需要包含sstream库
9+
std::cin.rdbuf(sin.rdbuf()); //重定向之后,cin的源就是sin中存的字符串
10+
int i;
11+
double d;
12+
char str[50];
13+
std::cin >> i >> d >> str;
14+
std::cout << i << '\n' << d << '\n' << str << '\n';
15+
std::cin >> str;
16+
std::cout << str << std::endl;
2017
return 0;
2118
}

.vscode/Test.exe

60.2 KB
Binary file not shown.

generalized_parts/13_input_output_streams_overview.tex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
\chapter{输入/输出流简介}
22
现在来到泛讲篇的最后一章,让我们来看一下输入/输出流的相关知识。\par
3-
一个基本的冯·诺依曼结构\footnote{冯·诺依曼结构(Von Neumann architecture),是一种存储程序逻辑架构。当今的主流计算机几乎都是依托于冯·诺依曼结构的。}计算机包含五个部分:控制器、运算器、存储器、输入设备和输出设备
3+
一个基本的冯·诺依曼结构\footnote{冯·诺依曼结构(Von Neumann architecture),是一种存储程序逻辑架构。当今的主流计算机几乎都是依托于冯·诺依曼结构的。}计算机包含五个部分:控制器、运算器、存储器、输入设备和输出设备,如图13.1所示。\par
44
\begin{figure}[htbp]
55
\centering
66
\includegraphics[width=.5\textwidth]{../images/generalized_parts/13_von_neumann_architecture.png}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
\section{信息在流中的传递}
2+
\subsection*{什么是流?}
3+
程序与外界的一切交互都是依靠字符的\textbf{输入(Input)}和\textbf{输出(Output)}完成的。我们可以想像一条流水线,我们的输入字符从输入设备——比如键盘中产生,经过流水线,一个个地被程序接收。这就是\textbf{流(Stream)}。\par
4+
对于输出信息来说,它也有一条(其实不止)流水线。输出字符从程序中产生,经过这条流水线,就能一个个地被输出设备——比如显示器所接收。\par
5+
\begin{figure}[htbp]
6+
\centering
7+
\includegraphics[width=\textwidth]{../images/generalized_parts/13_input_output_stream.drawio.png}
8+
\caption{程序的输入输出流}
9+
\footnotesize{仅供示意,输入内容与输出内容无因果关系}
10+
\end{figure}
11+
如图 \lstinline@13.2@所示,我们可以通过键盘输入一系列的内容到程序中,这时程序可以从输入流中逐个字符地读取我们的输入信息。程序还可以通过输出流把要输出的内容逐个字符地输出到相应的输出设备中,从而变成我们能在显示器中看到的信息。\par
12+
总而言之,在流中传递的所有``信息'',都是以字符为单位的。所有的输入,都可以看作是字符输入;所有的输出,都可以看作是字符输出。当程序需要我们输入字符的时候,我们输入的是字符;当程序需要我们输入整数或者浮点数的时候,我们输入的也是字符。那么问题来了:程序要怎么把我们输入的``字符''变成保存在整型/浮点型变量中的``''呢?这就要依靠 \lstinline@std::basic_istream@ 类模板中定义的重载运算符 \lstinline@>>@ 了。\par
13+
\lstinline@std::basic_istream@ 提供了一套方法,这样就允许我们从输入流的若干字符当中整理出有效信息,并把这个值赋给对应的变量或对象。与 \lstinline@std::basic_istream@ 相关的 \lstinline@>>@ 运算符有很多重载,以下是其中的一部分,包括成员函数和非成员函数:
14+
\begin{lstlisting}
15+
basic_istream& basic_istream::operator>>(int &value); //向int变量中输入
16+
//还有大量关于有符号/无符号的各种整型的重载
17+
basic_istream& basic_istream::operator>>(double &value);
18+
//还有关于float和long double的重载
19+
template< class CharT, class Traits>
20+
basic_istream<CharT, Traits>& operator>>(
21+
basic_istream<CharT, Traits> &st,
22+
CharT *s
23+
); //向字符串中输入;也有CharT&的重载,可以向字符中输入
24+
template< class CharT, class Traits, class Allocator >
25+
std::basic_istream<CharT, Traits>& operator>>(
26+
std::basic_istream<CharT, Traits> &is,
27+
std::basic_string<CharT, Traits, Allocator> &str
28+
); //向string对象中输入
29+
\end{lstlisting}
30+
假如我们要输入一个 \lstinline@int@ 型变量的值,那么程序就会调用 \lstinline@std::basic_istream::operator>>(int&)@。这个函数可以把读取到的字符信息提取(Extract)出来,从而赋值给对应的变量,这样就完成了一个输入操作。\par
31+
同样的道理,当我们需要输出一个什么内容的时候,\lstinline@std::basic_ostream@ 相关的 \lstinline@<<@ 运算符重载就可以根据对应的类型,把整型或者浮点型或者其它类型的数据全都变成字符来输出。\par
32+
\subsection*{输入源/输出目标与重定向}
33+
对于一个流来说,字符信息从哪里来,哪里就是它的源(Source);字符信息要到哪里去,哪里就是它的目标(Target)。对于标准输入输出来说,程序输入流的源就是键盘,目标就是程序本身;程序输出流的源就是程序本身,目标就是显示器。\par
34+
C语言来说有三种标准输入/输出——\lstinline@stdin@, \lstinline@stdout@, \lstinline@stderr@,分别表示标准输入、标准输出和标准错误输出。而C++是兼容C语言的。C++来说在 \lstinline@std@ 命名空间中定义了八个标准输入/输出流对象,我们用 \lstinline@#include<iostream>@ 即可包含它们。这八个对象可以对应到C语言的三种标准输入/输出。
35+
\begin{itemize}
36+
\item \lstinline@std::cin@ 和 \lstinline@std::wcin@ 用于控制标准输入,对应C语言中的 \lstinline@stdin@;
37+
\item \lstinline@std::cout@ 和 \lstinline@std::wcout@ 用于控制标准输出,对应C语言中的 \lstinline@stdout@;
38+
\item \lstinline@std::clog@, \lstinline@std::cerr@, \lstinline@std::wclog@ 和 \lstinline@std::wcerr@ 用于控制标准错误输出,对应C语言中的 \lstinline@stderr@。
39+
\end{itemize}
40+
这八个对象中,带 \lstinline@w@ 前缀的四个表示宽字符输入/输出。我们目前不用也不讲。而 \lstinline@std::clog@ 与 \lstinline@std::cerr@ 的区别在于前者是带有缓冲区的,而后者没有。我们稍后来介绍缓冲区机制。\par
41+
有些时候,我们会需要改变输入的源,或者改变输出的目标。我们可能需要从某个文件中读入信息,或者向某个文件中写入错误日志(这就可以用 \lstinline@std::clog@ 了)。C语言提供 \lstinline@freopen@ 之类的语法来允许我们进行\textbf{重定向(Redirection)},也就是改变源或者目标的位置。在C++中,我们可以通过 \lstinline@rdbuf@ 等成员函数来进行重定向。具体内容就留待精讲篇再介绍吧。\par
42+
\subsection*{缓冲区}
43+
在进行文件操作的时候,一个程序可能会频繁地从文件中不断读取少量的信息(比如一个不超过10字符长度的整数),然后自顾自地去进行下一步操作;过一会儿它又来了,又是读取一点点信息就走了。这种挤牙膏式的数据存取并不经济,因为外存或许能够一次性通过这个流传输1024字节(甚至更多)的数据,但我们却要分成几十上百次来完成,那么效率低也就不奇怪了\footnote{程序访问外存(文件中的信息存储于此)的速度要比访问内存(程序数据通常存储于此)的速度慢得多,我们在第一章中就提及过了。}。\par
44+
为了提高效率,输入/输出一般会使用\textbf{缓冲区(Buffer)}。缓冲区是程序在内存中分配的的一段临时使用区域。当程序从外界(尤其是外存中的文件)读取内容时,它充分利用这一次读取的机会,一次性读取尽可能多的内容。那些尚不需要的内容会被储存在缓冲区中。等到下次输入时,程序就不需要从外界获取信息了,而是直接从缓冲区(在内存中)获取,这样效率就高了。\par
45+
打个比方,你有一个小号的水杯。为了喝水,你必须频繁地去外面的水房打水。而缓冲区就像一个水壶,你可以去水房用水壶一次性多接点水。然后当你想要喝水时,你就可以从手边的水壶里直接倒出水来,不用总是拿着杯子去外面接水了。\par
46+
输出缓冲区也是一样的道理,程序可以先把要输出的内容缓存起来,然后再一次性输出到显示器或者文件当中。这就好像,我们有了一个垃圾桶之后就不用每次出门扔垃圾了,可以存一袋再一起扔。(这个比喻当然不是很恰当,输出内容可未必是垃圾)\par
47+
但是有些时候,有些信息是不能缓存的,比如运行时的报错信息(异常信息)。如果使用缓冲区的话,就存在一种风险:程序通过 \lstinline@std::cout@ 输出了报错信息,但是报错信息还留在缓冲区里没出来,用户没看到,还继续一意孤行地在错误的道路上渐行渐远呢。\par
48+
这个时候我们就应该使用 \lstinline@std::cerr@ 了。还记得我们上文怎么说的吗?这个对象是没有缓冲区的。没有缓冲区当然会导致挤牙膏一样的低效输出,但是——我们本来就不是为了用它输出正常信息的。什么时候我们可能用它呢?比如说,异常处理。
49+
\begin{lstlisting}
50+
try {
51+
//...
52+
} catch (const std::exception &msg) {
53+
std::cerr << "An exception has been caught:\n" << msg.what();
54+
}
55+
\end{lstlisting}
56+
对于异常处理来说,使用 \lstinline@std::cerr@ 就不会存在缓冲区风险了。\par
57+
如果我们有需要手动刷新输出缓冲区的话,可以调用 \lstinline@std::ostream@ 对象的 \lstinline@flush@ 成员函数。\par
58+
如果我们还同时有换行需求的话,那么我们可以不用手动 \lstinline@flush@ 了,直接写一个 \lstinline@std::cout<<std::endl@ 就行。这个语句就意味着两个操作:输出一个换行符,然后顺便刷新缓冲区。\par
59+
当然,这也就意味着,如果我们要进行文件操作之类的话,就要少用 \lstinline@std::endl@ 来换行了,应该尽可能使用 \lstinline@'\n'@ 这样的操作。否则就会不断刷新缓冲区,和挤牙膏没什么区别了。\par
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
\section{流输入/输出\textbf{iostream}}
2+
\subsection*{输入信息中的分隔符}
3+
有的时候我们会遇到需要一次性输入多个数据的情况,这时我们的选择是用空格来分隔开。
4+
\begin{lstlisting}
5+
std::istringstream sin {"25 1.3 Alan Turing"}; //需要包含sstream库
6+
std::cin.rdbuf(sin.rdbuf()); //重定向之后,cin的源就是sin中存的字符串
7+
int i;
8+
double d;
9+
char str[50];
10+
std::cin >> i >> d >> str;
11+
std::cout << i << '\n' << d << '\n' << str << '\n';
12+
std::cin >> str;
13+
std::cout << str << std::endl;
14+
\end{lstlisting}
15+
在这里我们使用了 \lstinline@std::istringstream@ 对象来存储一段字符串输入,然后让 \lstinline@std::cin@ 重定向到它。这样,我们就可以省去了运行程序时再输入内容的麻烦,而是直接把输入内容也写到代码里——无论输入流的源是什么,它们的效果都相同。\par
16+
这段代码的运行结果是:\\\noindent\rule{\linewidth}{.2pt}\texttt{
17+
25\\
18+
1.3\\
19+
Alan\\
20+
Turing
21+
}\\\noindent\rule{\linewidth}{.2pt}\par
22+
在输入信息中,\texttt{25} 和 \texttt{1.3} 之间的空格就是一个\textbf{分隔符(Delimiter)}。 在处理输入的时候,程序一旦遇到这样的分隔符,就会暂停读取输入,并把当前已经获得的输入内容(字符 \texttt{2} 和 \texttt{5} )处理成一个数据,赋值给 \lstinline@i@;接下来,它会无视下一位的空格\footnote{这个空格符作为流的一部分,仍然要被程序所接收。但是当 \lstinline@std::cin@ 发现这是一个空格符的时候,它就会什么也不做——表现出来就是无视了空格。},把后面的 \texttt{1.3} 读入其中,然后再次在空格符之前止步,把这些字符处理成数据,赋值给 \lstinline@d@;接收,它又在另一个空格符之前停下,把 \texttt{Alan} 复制给 \lstinline@str@;最后,它在文件结尾字符 \texttt{EOF}\footnote{EOF(End of file)不是一个ASCII字符(虽然它有未指明的ASCII值,通常为\texttt{-1}),但它可以用来表示文件的结尾。当输入流对象读到文件结尾字符时,输入流对象的状态发生改变,输入也就停止了。}之前停下,把 \texttt{Turing} 复制给 \lstinline@str@。于是我们就能看到这样的输出结果了。\par
57.9 KB
Binary file not shown.
43.5 KB
Loading

main.aux

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -243,19 +243,22 @@
243243
\@writefile{lof}{\addvspace {10.0pt}}
244244
\@writefile{lot}{\addvspace {10.0pt}}
245245
\@writefile{lof}{\contentsline {figure}{\numberline {13.1}{\ignorespaces 冯·诺依曼结构示意图}}{365}{figure.13.1}\protected@file@percent }
246+
\@writefile{toc}{\contentsline {section}{\numberline {13.1}信息在流中的传递}{365}{section.13.1}\protected@file@percent }
247+
\@writefile{lof}{\contentsline {figure}{\numberline {13.2}{\ignorespaces 程序的输入输出流}}{366}{figure.13.2}\protected@file@percent }
248+
\@writefile{toc}{\contentsline {section}{\numberline {13.2}}{368}{section.13.2}\protected@file@percent }
246249
\gdef \LT@i {\LT@entry
247250
{1}{42.00002pt}\LT@entry
248251
{1}{136.19997pt}\LT@entry
249252
{1}{117.00002pt}\LT@entry
250253
{1}{52.00002pt}\LT@entry
251254
{1}{86.48302pt}}
252-
\@writefile{toc}{\contentsline {part}{精讲篇}{369}{part*.249}\protected@file@percent }
253-
\@writefile{toc}{\contentsline {chapter}{\numberline {附录 A\hspace {.3em}}C++运算符基本属性}{369}{appendix.A}\protected@file@percent }
255+
\@writefile{toc}{\contentsline {part}{精讲篇}{371}{part*.252}\protected@file@percent }
256+
\@writefile{toc}{\contentsline {chapter}{\numberline {附录 A\hspace {.3em}}C++运算符基本属性}{371}{appendix.A}\protected@file@percent }
254257
\@writefile{lof}{\addvspace {10.0pt}}
255258
\@writefile{lot}{\addvspace {10.0pt}}
256-
\newlabel{ch:appendix_A}{{A}{369}{C++运算符基本属性}{appendix.A}{}}
257-
\@writefile{lot}{\contentsline {table}{\numberline {A.1}{截至C++17的所有运算符}}{369}{table.A.1}\protected@file@percent }
258-
\newlabel{tab:A-1}{{A.1}{369}{截至C++17的所有运算符}{table.A.1}{}}
259+
\newlabel{ch:appendix_A}{{A}{371}{C++运算符基本属性}{appendix.A}{}}
260+
\@writefile{lot}{\contentsline {table}{\numberline {A.1}{截至C++17的所有运算符}}{371}{table.A.1}\protected@file@percent }
261+
\newlabel{tab:A-1}{{A.1}{371}{截至C++17的所有运算符}{table.A.1}{}}
259262
\gdef \LT@ii {\LT@entry
260263
{1}{33.67001pt}\LT@entry
261264
{1}{33.81001pt}\LT@entry
@@ -267,11 +270,11 @@
267270
{1}{26.72002pt}\LT@entry
268271
{1}{27.283pt}\LT@entry
269272
{1}{86.44002pt}}
270-
\@writefile{toc}{\contentsline {chapter}{\numberline {附录 B\hspace {.3em}}ASCII码表(0到127)}{371}{appendix.B}\protected@file@percent }
273+
\@writefile{toc}{\contentsline {chapter}{\numberline {附录 B\hspace {.3em}}ASCII码表(0到127)}{373}{appendix.B}\protected@file@percent }
271274
\@writefile{lof}{\addvspace {10.0pt}}
272275
\@writefile{lot}{\addvspace {10.0pt}}
273-
\@writefile{lot}{\contentsline {table}{\numberline {B.1}{33个ASCII控制字符}}{371}{table.B.1}\protected@file@percent }
274-
\newlabel{tab:B-1}{{B.1}{371}{33个ASCII控制字符}{table.B.1}{}}
276+
\@writefile{lot}{\contentsline {table}{\numberline {B.1}{33个ASCII控制字符}}{373}{table.B.1}\protected@file@percent }
277+
\newlabel{tab:B-1}{{B.1}{373}{33个ASCII控制字符}{table.B.1}{}}
275278
\gdef \LT@iii {\LT@entry
276279
{1}{33.67001pt}\LT@entry
277280
{1}{33.81001pt}\LT@entry
@@ -285,20 +288,20 @@
285288
{1}{33.67001pt}\LT@entry
286289
{1}{33.81001pt}\LT@entry
287290
{1}{26.72002pt}}
288-
\@writefile{lot}{\contentsline {table}{\numberline {B.2}{95个ASCII可打印字符}}{372}{table.B.2}\protected@file@percent }
289-
\newlabel{tab:B-2}{{B.2}{372}{95个ASCII可打印字符}{table.B.2}{}}
290-
\@writefile{toc}{\contentsline {chapter}{\numberline {附录 C\hspace {.3em}}相关数学知识}{373}{appendix.C}\protected@file@percent }
291+
\@writefile{lot}{\contentsline {table}{\numberline {B.2}{95个ASCII可打印字符}}{374}{table.B.2}\protected@file@percent }
292+
\newlabel{tab:B-2}{{B.2}{374}{95个ASCII可打印字符}{table.B.2}{}}
293+
\@writefile{toc}{\contentsline {chapter}{\numberline {附录 C\hspace {.3em}}相关数学知识}{375}{appendix.C}\protected@file@percent }
291294
\@writefile{lof}{\addvspace {10.0pt}}
292295
\@writefile{lot}{\addvspace {10.0pt}}
293-
\@writefile{toc}{\contentsline {section}{\numberline {C.1}数制转换}{373}{section.C.1}\protected@file@percent }
294-
\@writefile{lof}{\contentsline {figure}{\numberline {C.1}{\ignorespaces 一个简单的数字时钟}}{373}{figure.C.1}\protected@file@percent }
295-
\@writefile{lof}{\contentsline {figure}{\numberline {C.2}{\ignorespaces 从计数到乘方}}{374}{figure.C.2}\protected@file@percent }
296-
\@writefile{lof}{\contentsline {figure}{\numberline {C.3}{\ignorespaces 一个12进制乘法表}}{375}{figure.C.3}\protected@file@percent }
297-
\@writefile{lof}{\contentsline {figure}{\numberline {C.4}{\ignorespaces $(1a.c3)_{16}$的形式化表示}}{377}{figure.C.4}\protected@file@percent }
298-
\@writefile{lof}{\contentsline {figure}{\numberline {C.5}{\ignorespaces 通过短除法把十进制数转换成$R$进制}}{380}{figure.C.5}\protected@file@percent }
299-
\@writefile{lof}{\contentsline {figure}{\numberline {C.6}{\ignorespaces 二进制与八进制的转换}}{381}{figure.C.6}\protected@file@percent }
300-
\@writefile{lof}{\contentsline {figure}{\numberline {C.7}{\ignorespaces 二进制与十六进制的转换}}{382}{figure.C.7}\protected@file@percent }
301-
\@writefile{toc}{\contentsline {section}{\numberline {C.2}布尔代数基础}{382}{section.C.2}\protected@file@percent }
302-
\@writefile{lof}{\contentsline {figure}{\numberline {C.8}{\ignorespaces 玛雅数字与阿拉伯数字的对应关系}}{383}{figure.C.8}\protected@file@percent }
303-
\@writefile{toc}{\contentsline {chapter}{跋}{385}{appendix*.258}\protected@file@percent }
304-
\gdef \@abspage@last{394}
296+
\@writefile{toc}{\contentsline {section}{\numberline {C.1}数制转换}{375}{section.C.1}\protected@file@percent }
297+
\@writefile{lof}{\contentsline {figure}{\numberline {C.1}{\ignorespaces 一个简单的数字时钟}}{375}{figure.C.1}\protected@file@percent }
298+
\@writefile{lof}{\contentsline {figure}{\numberline {C.2}{\ignorespaces 从计数到乘方}}{376}{figure.C.2}\protected@file@percent }
299+
\@writefile{lof}{\contentsline {figure}{\numberline {C.3}{\ignorespaces 一个12进制乘法表}}{377}{figure.C.3}\protected@file@percent }
300+
\@writefile{lof}{\contentsline {figure}{\numberline {C.4}{\ignorespaces $(1a.c3)_{16}$的形式化表示}}{379}{figure.C.4}\protected@file@percent }
301+
\@writefile{lof}{\contentsline {figure}{\numberline {C.5}{\ignorespaces 通过短除法把十进制数转换成$R$进制}}{382}{figure.C.5}\protected@file@percent }
302+
\@writefile{lof}{\contentsline {figure}{\numberline {C.6}{\ignorespaces 二进制与八进制的转换}}{383}{figure.C.6}\protected@file@percent }
303+
\@writefile{lof}{\contentsline {figure}{\numberline {C.7}{\ignorespaces 二进制与十六进制的转换}}{384}{figure.C.7}\protected@file@percent }
304+
\@writefile{toc}{\contentsline {section}{\numberline {C.2}布尔代数基础}{384}{section.C.2}\protected@file@percent }
305+
\@writefile{lof}{\contentsline {figure}{\numberline {C.8}{\ignorespaces 玛雅数字与阿拉伯数字的对应关系}}{385}{figure.C.8}\protected@file@percent }
306+
\@writefile{toc}{\contentsline {chapter}{跋}{387}{appendix*.261}\protected@file@percent }
307+
\gdef \@abspage@last{396}

0 commit comments

Comments
 (0)