1 C++输入输出综述
C++ IO首先建立在为Unix环境开发的原始库函数上;ANSI C正式承认这个库时,将其称为标准输入/输出包;
IO相关类定义在头文件iostream和fstream,这些类不是正式语言定义的组成部分,cin,istream都不是关键字。
1.1 流和缓冲
(1)流简介:
- C++程序将输入和输出看作字符流;对于输入来说,程序从输入流中抽取字符,对于输出来说,程序向输出流中插入字符;
- 输入流可以来自键盘、存储设备或者其他程序;输出流可以输出至显示器、打印机、存储设备或者其他程序。
- 流是程序与流源或流目的之间的中介,这样C++就可以对来源不同的字符做相同处理。
(2)管理输入:
- 两个阶段:将流与程序绑定在一起,将流与源绑定在一起
(3)管理输出:
- 两个阶段:将流与目的绑定在一起,将流与程序绑定在一起
(4)缓冲区简介
缓冲区就是一块存储空间,它是为了匹配程序处理速度和外设处理速度;比如程序一次处理1byte,但是磁盘一次读取512bytes;又或者程序一次处理1byte,可以1byte地从磁盘读取,但是由于硬件读取一次数据复杂且操作慢,因此使用缓冲区可以加快程序处理速度。
flushing the buffer:刷新缓冲区就是清空缓冲区地内容以备下次使用。
1.2 输入输出中比较重要的类
- streambuf:提供缓冲区,有成员方法 填满缓冲区、获取缓冲区内容、刷新缓冲区、管理缓冲区
- ios_base:表示流的一般属性 比如文件是否打开、是二进制流还是文本流等等
- ios:基于ios_base,并且它包含了一个指针成员指向一个streambuf对象
- ostream:继承自ios类并提供了输出方法
- istream:继承自ios类并提供了输入方法
- iostream:继承自ostream类和istream类
1.3 C++11 I/O新特性
- ostream.h转换为ostream,将ostream类放置到std命名空间中
- I/O类被重写,开发了I/O类模板包括basic_istream<charT,traits>和basic_ostream<charT, traits>。实现了char,wchar_t具体化;istream和ostream是char的具体化,cout输出字符流,wistream和wstream是wchar_t的具体化,wcout用于输出宽字符流。
- ios基类中的一些独立与类型的信息被移动到ios_base类中,比如格式化常量ios::fixed变为ios_base::fixed,还新增了一些常量
1.4 包含iostream头文件时会自动创建八个流对象(4个用于窄字符流,4个用于宽字符流)
- cin对象:对应标准输入流,默认情况下这个流与标准输入设备匹配(键盘);wcin对象用于wchar_t类型;
- cout对象:对应标准输出流,默认情况下这个流与标准输出设备匹配(显示器),借助streambuf管理流;wcout对象用于wchar_t类型;
- cerr对象:对应于标准错误流(可以用于显示错误信息),默认情况下这个流与标准输出设备匹配(显示器),这个流是不缓冲的;wcerr对象用于wchar_t类型;不受重定向的影响,即使重定向了输入输出流,错误信息还是打印到显示器上
- clog对象:对应于标准错误流,默认情况下这个流与标准输出设备匹配(显示器),这个流是缓冲的;wclog对象用于wchar_t类型。不受重定向的影响,即使重定向了输入输出流,错误信息还是打印到显示器上
1.4 重定向
修改标准输入和标准输出关联的工具。(比如输出到文件,而不是显示器)
2 cout的使用
当创建cout类时会自动打开一个流,创建一个缓冲区,并将流和缓冲区联系起来
C++在输出时将数据看作字符流。
2.1 显示各种类型的数据
各种char字符可以直接显示,但是对于各种数据包括int,long,float,double就无法直接解析为字符了
C++中将使用cout的<<称为插入操作符,意味着将右侧的信息流传递到左侧(因为<<是左移运算符,相当于给了个方便记忆的解释)
因此cout类重载了<<操作符,重载了适合多种数据类型的<<操作符成员函数,将数据类型转换为文本形式的字符流;以下数据类型皆被重载:unsigned char、signed char、char、short、unsigned short、int、unsigned int、long、unsigned long、long long (C++11)、unsigned long long (C++11)、float、double、long double
重载原型为:ostream & operator<<(type);
2.2 输出与指针
ostream为const signed char *、const unsigned char *、const char *、void *重载了<<操作符,因此,可以使用cout<<输出显示字符串;这个方法使用\0来判断是否停止显示字符。
如果要显示字符串的地址,由于传递指针输出了整个字符串,因此将其强制转换为void *类型可以显示字符串的地址。
举例:
cout << "输出与指针*********************************************************************" << endl;
int eggs = 12;
const char* amount = "dozen";
cout << &eggs; // prints address of eggs variable
cout << amount; // prints the string "dozen"
cout << (void*)amount<<endl; // prints the address of the "dozen" string
运行结果:
输出与指针*********************************************************************
008FFD9Cdozen0041BC80
2.3 输出连接
ostream & operator<<(type);
根据上述函数原型可以知道,返回值是ostream类型的引用,这就可以使得cout<<实现输出连接
cout << “We have " << count << " unhatched chickens.\n”;
举例:
cout << "输出连接***********************************************************************" << endl;
cout << "We have " << eggs << " unhatched chickens.\n";
运行结果:
输出连接***********************************************************************
We have 12 unhatched chickens.
2.4 输出字符cout.put()
原型:
template <class type>//type为char或wchar_t
ostream & put(type);
当传递的实参不是char或wchar_t时,会执行自动转换将其转换为char或wchar_t类型,这个很适合早期发行版本2.0,在那些版本中,使用int值表示字符。
cout << 'W';//在早期发行版本2.0,这个会输出W的ASCII码,当前版本会输出字符W
cout.put('W');//在早期发行版本2.0,这个会输出W字符,当前版本会输出W字符
一些编译器为char, unsigned char, and signed char重载了put(),但是这会给自动转换int实参带来歧义,因为int可以转换为其中任何一个。
举例:
cout << "cout.put()*********************************************************************" << endl;
cout.put('W'); // display the W character
cout.put('I').put('t'); // displaying It with two put() calls
cout.put(65); // display the A character
cout.put(66.3); // display the B character
cout.put(65); // display the A character
cout.put(66.3) << endl; // display the B character
运行结果:
cout.put()*********************************************************************
WItABAB
2.5 输出字符串cout.write()
原型:
basic_ostream<charT,traits>& write(const char_type* s, streamsize n);
第一个参数提供了需要显示的字符串地址,第二个参数指示了显示几个字符;cout.write()成员函数不会判断字符串是否结尾,指定显示几个字符就显示几个,即使它过界了。返回值为cout,说明支持输出连接
针对write非char类型的数据,程序根据8bit存储空间的内容来决定显示为哪个字符,超过8bit的数据类型,则分为几个字符显示。
举例:
cout << "cout.write()*******************************************************************" << endl;
const char* state1 = "Florida";
const char* state2 = "Kansas";
const char* state3 = "Euphoria";
int len = std::strlen(state2);
cout << "Increasing loop index:\n";
int i;
for (i = 1; i <= len; i++)
{
cout.write(state2, i);
cout << endl;
}
// concatenate output
cout << "Decreasing loop index:\n";
for (i = len; i > 0; i--)
cout.write(state2, i) << endl;
// exceed string length
cout << "Exceeding string length:\n";
cout.write(state2, len + 5) << endl;
long val = 560031841;
cout.write((char*)&val, sizeof(long))<<endl;
运行结果:
cout.write()*******************************************************************
Increasing loop index:
K
Ka
Kan
Kans
Kansa
Kansas
Decreasing loop index:
Kansas
Kansa
Kans
Kan
Ka
K
Exceeding string length:
KansasEup
aha!
2.6 清空输出缓存
缓存一般是512bytes或者其倍数。
在显示器输出时,三种情况可清空缓存
1.发送一个新行给缓冲器,endl
2.当输入挂起时
3.使用工具 flush()函数
使用方法:flush(cout);或者cout<<flush;(这个重载了<<操作符)
举例:
cout << "清空输出缓存*******************************************************************" << endl;
cout << "Enter a number: ";
float num;
cin >> num;
cout << "Hello, good-looking! " << flush;
cout << "Wait just a moment, please." << endl;
运行结果:
清空输出缓存*******************************************************************
Enter a number: 99
Hello, good-looking! Wait just a moment, please.
2.7 cout针对不同数据类型的输出格式
(1)char:占用一个字符的位置
(2)整形:占用足够显示它的字符位置数(十位数占用两个字符位置,个位数占用一个字符位置),如果是负数要在前面加一个-号
(3)字符串:占用字符串长度的字符位置数
(4)浮点型:显示的有效位数为6位,尾部的0不显示
注意事项:不同地区可能有不同的格式:比如欧洲的小数点用,表示而不是.表示;数据之间需要手动添加间隔符将两个数字分开,否则会连续显示。
举例:
cout << "cout针对不同数据类型的输出格式***************************************************" << endl;
cout << "12345678901234567890\n";
char ch = 'K';
int t = 273;
cout << ch << ":\n";
cout << t << ":\n";
cout << -t << ":\n";
double f1 = 1.200;
cout << f1 << ":\n";
cout << (f1 + 1.0 / 9.0) << ":\n";
double f2 = 1.67E2;
cout << f2 << ":\n";
f2 += 1.0 / 9.0;
cout << f2 << ":\n";
cout << (f2 * 1.0e4) << ":\n";
double f3 = 2.3e-4;
cout << f3 << ":\n";
cout << f3 / 10 << ":\n";
运行结果:
cout针对不同数据类型的输出格式***************************************************
12345678901234567890
K:
273:
-273:
1.2:
1.31111:
167:
167.111:
1.67111e+06:
0.00023:
2.3e-05:
2.8 cout以不同进制显示整数
ios_base是ios的基类,ios是一个模板类包含了char和wchar_t的专门化,ios_base包含了非模板的特征
流操纵符dec,hex,oct:ios_base中有工具dec,hex,oct使得数据以不同进制显示;dec(),hex(),oct()是函数,并且重载了<<操作符&