C++语言本身不提供输入与输出的操作,但是可以使用标准库提供的输入与输出功能,即程序中独立于设备的 I/O 操作。
输入与输出包括:
- 标准的输入输出(标准 I/O),即对系统指定的标准设备的 I/O 操作。用 cin 和 cout 从键盘输入数据,结果输出到显示器屏幕。
- 文件的输入输出(文件 I/O),即以外存中的文件为对象进行输入和输出。包括从磁盘文件输入数据,或将数据输出到磁盘文件。
- 字符串输入输出(串 I/O ), 即对内存中指定空间进行输入和输出。通常指定一个字符数组作为存储空间存储任何信息。
输入输出流
C++的输入输出流可以看作外部设备和计算机内存之间流动的字节序列,这些字节中的数据按照一定的顺序从一个对象传送到另一个对象。在输入操作时,字节流从输入设备流向内存;输出操作时,字节流从内存流向输出设备。流中的内容可以是 ASCII 字符、二进制形式的数据、图形图像、数字音频视频或其他形式的信息。
- 流:程序中输入或输出设备的抽象,它表示了信息从源到目的端的流动。
- 输入流:可以是任何序列的数据源(磁盘文件或键盘),标准库定义了一个标准的输入流,通常与键盘有关。
- 输出流:物理实现为能传送字节的任何设备。一般情况下输出流对应显示器、磁盘文件或打印机。标准库中定义了标准输出流及两个标准错误流,这些输出流一般与显示器屏幕有关。
流类
在C++中,输入输出被定义为类,I/O库中的类称为流类(stream class)。下面提供了 iostream 类库的继承和派生关系。其中,ios 是抽象基类。
常用:
- ostream:包含对输入输出流进行操作所需的基本操作,提供无格式和格式化的 I/O 操作。
- fstream:用于用户管理文件的输入输出操作,包括建立、读/写文件的各种操作接口。
- strstream:用于字符串流输入输出操作。
- iomanip:包含格式化输入输出操纵算子,用于指定数据输入输出格式。
用流类定义的对象称为流对象。cout 和 cin 并不是C++语言中提供的关键字,它们是 iostream 类的对象。
- cin:是istream的派生类istream_withassign 的对象,是键盘输入到内存的数据流,称为cin流或标准输入流。
- cout:是ostream的派生类ostream_withassign 的对象,是从内存输入到显示器的数据流,称为 cout流或标准输出流。
标准输入输出流
标准流对象是在std命名空间中定义的流对象。分别在头文件 iostream 中定义:
extern istream cin; //标准输入流对象
extern ostream cout; //标准输出流对象
extern ostream cerr; //标准错误流对象
extern ostream clog; //标准错误流对象
- cin :在istream中定义了成员函数operator >> (),实现多种类型输入。通过流提取运算符 (>>)从流中获取数据时,通常跳过输入流中的分隔符(空格、Tab键、换行符)。
- cout(console output):在ostream中定义了成员函数operator << (),实现多种类型输出。通过流插入运算符 (<<)将数据插入到输出流中。当向cout流插入一个 endl 时,不论缓冲区是否已满,都立即输出流中所有数据和一个换行符,并刷新流(清空缓冲区)。如果流中插入 '\n' ,则只输出换行。
- cerr:作用是向标准错误设备(standard error device)输出有关出错信息。cerr与cout的作用和用法相似,区别是:cout既可以传送到显示器输出,又可以重定向输出到磁盘文件。cerr只能显示到屏幕上。
- clog(console log):作用和cerr相同,都是在终端上显示出错信息。唯一区别是,cerr直接输出到显示器上,不经过缓冲区。clog 中的信息存放在缓冲区中,缓冲区满后或遇 endl 时向显示器输出。
格式输出
两种方法控制格式输出:
- 流对象的成员函数
- 控制符
控制符 | 作用 |
---|---|
dec | 转换整数的基数为十进制 |
oct | 转换整数的基数为八进制 |
hex | 转换整数的基数为十六进制 |
showbase | 在输出中显示基数指示符 |
uppercase | 十六进制输出时一律用大写字母 |
scientific | 科学计数法显示浮点数 |
fixed | 定点小数形式显示浮点数 |
showpoint | 把带有小数点浮点数值输入到流中 |
showpos | 正整数前加 ” + “ 号 |
unitbuf | 输出操作后立即刷新流 |
left | 输出数据在本域宽范围内左对齐 |
right | 输出数据在本域宽范围内右对齐 |
internal | 在符号位和基数指示符后填入 字符 |
boolalpha | 把bool值表示为字母true或false |
noboolalpha | 把bool值表示为数字1或0 |
endl | 在流缓存中写入一个换行符,并清空流 |
ends | 在流缓存中写入一个空格符,并清空流 |
flush | 把流缓存中的数据写入流中 |
常用的成员函数和实现同样功能的操作符如下:
控制符 | 成员函数 | 作用 |
---|---|---|
setfill(c) | flag(c) | 设置填充字符为字符常量或字符变量 |
setprecision(n) | precision(n) | 设置显示小数的精度为n位 |
setw(n) | width(n) | 设置域宽为n个字符 |
setbase(n) | 设置整数的基数为n( n=8,10,16) | |
setiosflags() | setf() | 设置输出格式的状态,括号中指定格式内容 |
resetiosflags() | unsetf() | 终止已设置输出格式的状态,括号中指定格式内容 |
下面例子将对基数进行简单设置:
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
int a = 12, b = 16;
cout<<"Output in octal:\n"<<setiosflags(ios::oct) //设置输出数的基数为8,即八进制表示
<<"a = "<<a<<", b = "<<b<<endl; //输出 a = 14, b = 20
cout<<"Outpur in decimal:\n";
cout.setf( ios::dec, ios::basefield ); //默认进制为10进制
cout<<"a = "<<a<<", b = "<<b<<endl; //格式符作用多个操作数
cout<<"Outpur in hexadecimal:\n"<<hex //使用操作符设置技术为16
<<"a = "<<a<<", b = "<<b<<endl; //输出 a = c, b = 10
return 0;
}
I/O流错误
从流的读取和写入数据的过程中,往往会发生错误。C++提供了检测 I/O 流状态的标志和成员函数。所有流类把流状态存储在状态字中,其中的特定标志位记录流处于正常状态或不同的错误状态。可以用类ios中的状态字的特定位测试流的状态。
标志 | 含义 |
---|---|
goodbit | 状态正常 |
eofbit | 文件结束符,当到达文件末尾时设置该标志 |
badbit | 当非法操作后流不能继续时设置该函数,会造成数据丢失,不可恢复 |
failbit | I/O操作失败时设置该标志,后续操作失败但数据未丢失,状态可回复 |
标志 | 含义 |
---|---|
good() | 如果在流对象中没有设置任何错误标志位,就返回true |
eof() | 如果在流对象中没有设置结束标志位 eofbit,就返回true |
bad() | 如果在流对象中没有设置错误标志位 badbit,就返回true |
fail() | 如果在流对象中没有设置结束标志位 badbit 或 failbit,就返回true |
注意:
- 当遇到相应的错误时,输入流中自动设置成相应的状态,我们可以调用状态检测标志去返回 bool 类型的结果,同样也可以对流状态进行主动设置 ios::eofbit 。
- 成员函数 rdstate() 用于返回流的错误状态。 cout.rdstate()
- 当流操作出现错误而中止程序时,需要改正错误并恢复流操作。而一但设置了某个标志,该标志就会一直保持下去,除非对其进行重新设置。调用成员函数clear()可以重新设置三个错误标志位,通常用于把一个流的状态恢复为正常,从而继续执行I/O操作。如cin.clear()。
- 由于默认参数位 ios::goodbit,该语句功能位清除 cin 错误状态,并为流设置 goofbit ,对 cin 执行输入操作或遇到问题时,用户可能需要调用函数 cin.clear( ios::failbit )为流设置 failbit 状态。
- 如果 badbit 和 failbit 有一个被置位, 成员函数 operator !() 就返回true。可以通过测试cin的值,判断流对象是否处于正常状态或提取操作是否成功。如 if(!cin) cout<<"Error!"; 其中,! cin 就是 ! cin.good()。
// testStreamState.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
#include <iomanip>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
cout<<"Before a bad input operator:" //输入正常流各状态值
<<"\n cin.rdstate(): "<<cin.rdstate() //流的状态
<<"\n cin.eof(): "<<cin.eof() //测试结束标志位
<<"\n cin.fail(): "<<cin.fail() //测试结束标志位
<<"\n cin.bad(): "<<cin.bad() //测试错误标志位
<<"\n cin.good(): "<<cin.good()<<"\n\n"; //测试正常状态
cin.clear();
int grade = 0;
cout<<"Expects an integer, but enter a charactor:";
cin>>grade;
//测试流出错状态值
if(!cin.good())
cerr<<"\a\n Invalid number."
<<"\n Error status in "<<cin.rdstate();
if(cin.eof())
{
cerr<<"\n End of file detected.";
return 0;
}
else if(cin.fail())
cerr<<"\n Only int number allowed.";
else if(cin.bad())
cerr<<"\n Keyboard is not working.";
else
cerr<<"\n Error.";
cout<<"\n After error:"<<setiosflags(ios::boolalpha) //把bool值表示为true或false
<<"\n cin.rdstate(): "<<cin.rdstate() //流的状态
<<"\n cin.eof(): "<<cin.eof() //测试结束标志位
<<"\n cin.fail(): "<<cin.fail() //测试结束标志位
<<"\n cin.bad(): "<<cin.bad() //测试错误标志位
<<"\n cin.good(): "<<cin.good()<<"\n\n"; //测试正常状态
return 0;
}
结果
Before a bad input operator:
cin.rdstate(): 0
cin.eof(): 0
cin.fail(): 0
cin.bad(): 0
cin.good(): 1
Expects an integer, but enter a charactor:a
Invalid number.
Error status in 2
Only int number allowed.
After error:
cin.rdstate(): 2
cin.eof(): false
cin.fail(): true
cin.bad(): false
cin.good(): false
字符的 I/O 函数
除了用于格式化流输入输出的插入和提取运算符之外,流类还有一些成员函数,可以把基于字符的数据传递给流,或从流传送基于字符的数据。
(1)输出字符函数 put():将单个字符写入流中,并在屏幕中显示该字符。 用法:cout.put('a');
(2)输入字符函数 get():从流中读取任意单个字符,如果到达文件末尾,函数返回EOF(End of File)。其中有三种用法:
- 无参数:a = cin.get();
- 有一个参数:cin.get(a);
- 有三个参数:cin.get(cArray, 10, '.'); 作用:从输入流中读取 10-1=9 个字符,赋给指定的数组cArray,如果遇到指定的终止符 ‘.’,则提前结束读取,并将终止符 ‘.’ 保存到数组中。
(3)输入字符串函数 getline():从输入流中读取一行字符。与三个参数的 get()相似,区别在于 getline() 从流中删除了分隔符,下一个要读取的是分隔符后面的字符。
while((c=cin.get())!=EOF) //输入: How are you?
cout.put(c); //输出: How //以任意分隔符结束
while(cin.get(c)!=EOF) //输入: How are you?
cout.put(c); //输出: How //以任意分隔符结束
cin.get(cArray,10,'.'); //输入: I love you
//输出: I love yo. //以终止符结尾
cin.getline(cArray,10,'.'); //输入: I love. you
//输出: I love //遇到终止符结尾,忽略终止符
cin.getline(cArray,10); //默认结束符位"回车符"
重载流插入和提取运算符
"<<" 和 ">>" 本事C++中被定义为位左移和位右移的运算符,在iostream.h中对其进行了重载,使之作为流插入和流提取运算符。ostream流类中重载 operator << () 为成员函数,如:
ostream &operator << (int);
ostream &operator << (float);
ostream &operator << (char);
而我们在使用时,很可能需要对类中的对象进行输出,因此我们可以自己通过重载函数、友元函数对流运算符进行重载,如下:
ostream& operator << (ostream& out, const char* pCh); //输出字符串
ostream& operator << (ostream& out, const char ch); //输出字符