C++的输入和输出

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
cof() 如果在流对象中没有设置结束标志位 eofbit,就返回true
bad() 如果在流对象中没有设置错误标志位 badbit,就返回true
fail() 如果在流对象中没有设置结束标志位 badbit 或 failbit,就返回true

注意:

  • 当遇到相应的错误时,输入流中自动设置成相应的状态,我们可以调用状态检测标志去返回 bool 类型的结果,同样也可以对流状态进行主动设置  ios::eofbit 。
  • 成员函数 restate() 用于返回流的错误状态。 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);      //输出字符
发布了50 篇原创文章 · 获赞 21 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/u012839256/article/details/104717650