流
流是根据连续传输特性命名的一种信息序列,也可以认为是一种抽象的数据结构。流不能直接被随机读写,而可以顺序读写,因此如果要取得其中的数据需要的时间开销和数据的位置相关。作为对比,一般的连续线性表(例如储存在内存中的数组)可以根据下标作为索引在常数时间复杂度内定位至其中的任一位置进行读写(随机读写)。流可以用来抽象低速存储介质(不支持随机读写)中的信息,例如硬盘和网络文件等。
在C语言中,流被实现为标准库实现的内部结构,通过文件指针(FILE*对象)可以表示流(外存储器中的文件也被作为流来进行读写),提供平台无关的操作方式。存在三种标准的流:标准输入流stdin、标准输出流stdout和标准错误输出流stderr。默认情况(不经过重定向)下,标准输入流在控制台程序中映射为键盘输入,后两者一般为控制台输出。scanf、printf等标准输入/输出函数专门对stdin和stdout进行操作,在库的底层往往和对应函数的流操作版本共用实现。例如scanf("%d", &i);相当于fscanf(stdin, "%d", &i);——也就是scanf等也是对流进行操作,只不过这里的流被隐含地限定为stdin/stdout。另外一个重点是提供了缓冲机制(标准错误输出流是无缓冲的),可以显著提升读写效率(如果直接使用平台相关的外部API、系统调用等,为了操作硬件可能需要频繁切换操作系统状态,效率很低)。同时由于缓冲的存在,顺序读写进行定位时的性能更加稳定(例如fseek之类对程序员而言基本是O(1),不管定位到哪里,时间开销基本没什么区别)。
C++继承了C语言中对流的操作方式,同时在标准库中(包含<iostream>、<fstream>等)对流操作进行另一个角度的封装。以上三个标准流的对应对象为cin、cout和cerr。对于这些对象的基本操作效果(也是它们存在的意义)在本质上和C是相同的(缓冲实现等细节有所区别;另外cin和cout是有缓冲的,cerr还是无缓冲的),只是使用的语言特性不同——例如可以根据参数类型在编译期确定输出的格式,配合运算符重载的operator<<和operator>>,而不需要在运行期解析格式控制字符串;使用cout<<endl而不用fflush(stdout)等等。