跳到主要内容

对输入输出缓冲区的理解:

缓冲区的存在可以屏蔽掉低级I/O的实现;由于低级I/O的实现依赖操作系统本身内核的实现,所以如果能够屏蔽这部分的差异,就可以很容易写出可移植的程序。 可以使用这部分的内容实现 “行” 读取的行为;对于计算机而言是没有 “行” 这个概念,有了这部分,我们就可以定义 “行” 的概念,然后解析缓冲区的内容,返回一个 “行”。 注:C语言除了有输入输出接口 scanf 和 printf,还有文件操作读写接口 fread/fwrite、fscanf/fprintf,以及字符串序列化反序列化接口 sprintf/snprintf/sscanf。

使用缓冲区有两个好处:

减少实际的物理读写次数; 缓冲区在创建时就被分配内存,这块内存区域一直被重用,可以减少动态分配和释放内存的开销,更容易地实现可移植程序; 可以实现“行”读取,即按行读取文件内容。这种方式可以方便地处理文本文件中每一行的数据,而不需要考虑每一行数据长度不同等问题。 实际上,“行”的概念是由人主动赋予计算机的,机器本身没有“行”的概念,只要按照一定的规则解析缓冲区中的内容,边能得到一个“行”的内容。

在计算机科学中,流(stream)是对一种有序连续且有方向性的数据的抽象描述。

I/O 发生在流中。流就是一串二进制编码。可以将流理解为一个系统与一个程序之间形成的一个通道,就像两地之间的河道一样。那么流本身就是一堆由01组成的二进制编码。

输入:字节流是从设备(如键盘、磁盘驱动器、网络连接等)流向内存; 输出:字节流是从内存流向设备。 我们都知道大小端机器,大端和小端就是字节序的两种形式,那么字节序列本质上就是一串二进制编码。

流的特点:

具有方向性;

有序且连续;

输入流、输出流是相对的。

为了实现流,C++提供了I/O标准库,其中每个类都被称为流或流类。

io

ios

C++提供了流输入输出库<ios>,所有的类都继承自ios_base ,它是 C++ 标准程序库中的一个类,定义于 <ios> 头文件中。它封装了 C++ 标准中的流输入输出中不依赖于读写的数据的类型的基本信息,如格式化信息、异常状态、事件回调函数等。

其中,ios为istream和ostream的父类,其他类都是直接或间接派生自ios类。istream 和 ostream 分别表示输入流和输出流,它们是 C++ iostream 库的基础。为了允许双向的输入/输出,由 istream 和 ostream 派生出了 iostream 类 。

其中,流输入操作符>>和流提取操作符<<用于从输入流中读取数据和向输出流中写入数据。

例如,使用cin >> x;可以从标准输入流中读取一个值并将其存储在变量x中。使用cout << x;可以将变量x的值写入标准输出流。

这些操作符可以链接起来,以便一次性读取或写入多个值。例如,使用cin >> x >> y;可以从标准输入流中读取两个值并分别存储在变量x和y中。使用cout << x << " " << y;可以将变量x和y的值以及一个空格字符写入标准输出流。

endl是一个操作符,用于在输出流中插入一个换行符并刷新该流。例如,使用cout << "Hello" << endl;可以在标准输出流中输出字符串"Hello",然后换行并刷新该流。在日常使用中,常用来当做换行符使用。

cin和cout的配合

cin是标准输入流对象,它一般使用行缓冲机制。当输入接收到回车的时候就会进行数据的刷新。程序的输入都建有一个缓冲区,即输入缓冲区。一次输入过程是这样的,当一次键盘输入结束时会将输入的数据存入输入缓冲区,而cin函数直接从输入缓冲区中取数据。

在执行cout语句时,先把插入的数据顺序存放在输出缓冲区中,直到输出缓冲区满或遇到cout语句中的endl(或\n, ends, flush)为止,此时将缓冲区中已有的数据一起输出,并清空缓冲区。

以空格和回车分割

cin和cout利用缓冲区进行输入输出操作,我们用cin输入时如果按空格或回车分隔数据,那么cout也会按相同规则读取,例如:

int main()
{
int a = 0, b = 0;
cin >> a;
cout << a << endl;

cin >> b;
cout << b << endl;
return 0;
}

这段代码中,虽然形式上是分别输入和输出,但实际上如果一次性输入变量a和变量b的值,并以空格分隔,那么cout两次都会从同一个缓冲区按空格为分隔读取。

(一次性)输入:

> 1 2
1
2

但是因为这个规则,当使用cin输入的数据类型是字符或字符串时,其内容不能包含空格,回车符也无法读入。如果包含空格,用cout输出时只会输出空格之前的内容:

int main()
{
string str;
cin >> str;
cout << str;
return 0;
}
> hello world
hello

hello 但实际上字符串中经常会出现空格,需要使用getline()读取。

getline() 函数有两种形式,一种是头文件 <istream> 中输入流成员函数;一种在头文件 <string> 中普通函数。它用于从输入流中读取多行用户输入,直到找到分隔符(即'\n')为止。

int main()
{
string str;
getline(cin, str);
cout << str;
return 0;
}

输入:

> hello world
hello world

getline() 函数有两个必需的参数和一个可选参数。第一个参数是输入流,它指定从哪个输入流中读取文本。第二个参数是字符串变量,它指定将读取的文本存储在哪个字符串变量中。

第三个可选参数是分隔符字符,它指定在遇到哪个字符时停止读取文本。如果未指定分隔符,则默认为换行符(\n)。

例如,在上面给出的 getline() 示例中,我们使用 std::cin 作为输入流,line 作为字符串变量,并使用默认的换行符作为分隔符。

Loading Comments...