1.C++输入和输出概述
1.1流和缓冲区
C++程序把输入和输出看作字节流。输入时,程序从输入流中抽取字节;输出时,程序将字节插入到输出流中。输入流中的字节可能来自键盘,也可能来自存储设备或其他程序。输出流中的字节可以流向屏幕、打印机、存储设备或其他程序。输入流和输出流均需要两个连接,文件端部提供了流的来源,程序端连接将流与程序进行连接。
使用缓冲区可以高效的处理输入和输出。C++程序通常在用户按下回车键时刷新输入缓冲区;在用户发送换行符时刷新输出缓冲区。
1.2流、缓冲区和iostream文件
iostream文件中包含了一些专门设计用来实现、管理流和缓冲区的类。
streambuf类为缓冲区提供了内存、缓冲区和管理缓冲区的办法;
ios_base类表示流的一般特征,如是否可读取、是二进制流还是文本流;
ios类基于ios_base,包括了一个指向streambuf对象的指针成员;
ostream从ios派生出来,提供了输出方法;
istream从ios派生出来,提供了输入方法;
iostream基于ostream和istream类,继承了输入和输出方法。
要使用这些工具,必须使用适当的类对象,例如,使用cout(ostream对象)来处理输出。创建一个这样的对象将打开一个流,自动创建缓冲区,并将其与流关联起来,同时使得能够使用类成员函数。
cin对象对应于标准输入流,默认情况下,这个流被关联到标准输入设备(通常为键盘)。
cout对象对应于标准输出流,默认情况下,这个流被关联到标准输出设备(通常为显示器)。
cerr对象对应于标准错误流,可用于显示错误消息。默认情况下,这个流被关联到标准输出设备(通常为显示器),这个流没有被缓冲。
clog对象对应于标准错误流,可用于显示错误消息。默认情况下,这个流被关联到标准输出设备(通常为显示器),这个流被缓冲。
对象代表流:创建一个对象,该对象包含了有关的所有数据成员。例如cout对象凭借streambuf对象的帮助,管理着流中的字节流。
1.3重定向
重定向使得能够该百年标准输入和标准输出。将输入输出和文件联系起来,而不是屏幕键盘。重定向用于不同的操作系统中的输入输出。对标准输入重定向并不会影响cerr或clog,错误信息依然会被显示到显示器上。如果重定向没有起作用,则选定的消息会被显示到屏幕上,如果程序输出被重定向到一个文件,第一条消息(被选定)将被发送到文件,而第二条消息(被选定)将发送到屏幕。
2.使用cout进行输出
ostream类最重要的任务之一是将数值类型(如int、float等)转换为以文本形式表示的字符流。需要将数据内部表示(二进制位模式)转换为由字符字节组成的输出流。
2.1重载的<<运算符
<<也叫插入运算符,是被重载的左移运算符。对于 char(unsigned signed ) 、short(unsigned signed) 、int(unsigned、signed)、float、double (long)、long(unsigned、long、 unsigned long long)数据类型都进行了左移运算符的重载,所以cout可以直接进行输出。
2.1.1输出和指针
ostream为下面的指针类型定义了插入运算符函数:
const signed char*、const unsigned char*、const char*、void*.
C++输出字符串(指针的方式来输出的),方法使用字符串中的终止空字符来确定何时停止显示字符。对于其它类型的指针,C++将其对应于void*,并打印地址的数值表示。要获得字符串地址,必须将其强制转换为void*类型。
2.1.2拼接输出
插入运算符的返回类型都是ostream&,返回掉队该运算符的对象,所以可以进行拼接输入,前几章重定向<<也是模仿了该技术。
2.2其他ostream方法
2.2.1put()
该方法用于显示字符,原型为:
ostream & put(char);
和运算符函数一样,该函数也返回一个指向调用对象的引用,可以用它拼接输出:
cout.put('w').put('I') ;
在原型何时的情况下,可以将数值型参数(int)用于put(),函数原型自动将参数转换为正确char值。
cout.put(65);
cout.put(66.3);
2.2.2write()
该方法用于显示字符串,该函数需要两个参数,第一个参数显示了字符串的地址,第二个参数指出要显示多少个字符串。cout.write()调用返回cout对象,可以将输出拼接起来,write()方法并不会在遇到空白字符时自动停止打印字符,而只是打印指定数目的字符,即使超过字符串的边界。
write()方法也可用于数值数据,将数字的地址强制转换为cahr*,这不会将数字转换为相应的字符,而是传输内存中存储的位表示,将把被个字节作为ASCII码进行解释。
#include<iostream>
using namespace std;
int main()
{
const char* s1= "Hello,my sweetheart!";
const char s2[] = "I been waiting for you all day.";
char ch = 'p';
cout.write(s2, strlen(s2));
cout << endl;
for (int i = 0; i < strlen(s1); i++)
{
cout.write(s1, i);
cout << endl;
}
cout.put(ch).put(ch + 1);
cout << 'o';
return 0;
}
2.3刷新输出缓冲区
通常,缓冲区位512字节或其整倍数,在屏幕输出时,程序不必等到缓冲区被填满。将换行符发送到缓冲区后,将刷新缓冲区;程序期待输入,将导致它立刻显示cout信息,即使输出字符串中没有换行符,否则程序将等待输入,而无法通过cout信息来提示用户。
如果不能实现在希望的时刻刷新输出,可以使用endl、flush两个控制符来强制刷新,flush刷新缓冲区,endl刷新缓冲区并且插入换行符。
cout<<"Hello"<<endl;
cout<<"Hello"<<flush;
或者
flush(cout);
2.4用cout进行格式化
ostream插入运算将值转换为文本格式。在默认情况下,格式化值的方式如下:
1.char值,如果代表可打印字符,作为一个字符显示在宽度为一个字符的字段中;
2.数值整型,将以十进制方式显示在刚好容纳该数字及符号的字段中;
3.字符串被显示在宽度等于该字符串长度的字段中;
4.浮点类型被显示为6位,末尾的0不显示(显示位数与存储精度无关)。数字以定点表示法还是科学计数法取决于它的值(指数大于等于6或小于等于-5,将使用科学计数法表示)。字段宽度将刚好容纳数字和负号。
因为每个值的显示宽度都等于它的长度,因此必须在显式地在值之间提供空格;否则,相邻地值将不会被分开。
2.4.1修改显示时使用的计数系统
要控制整数以十进制、十六进制还是八进制显示,可以使用dec、hex、和oct控制符。下面地函数调用将cout对象的计数格式状态设置为十六进制:
hex(cout);
完成上述设置后,程序将以十六进制形式打印整数,直到将格式状态设置为其他选项为止。控制符不是函数,因此不需要通过对象调用。
通常的使用方式为:
cout<<hex; 等价于hex(cout);
#include<iostream>
using namespace std;
int main()
{
const char* s1 = "Hello,my sweetheart!";
const char s2[] = "I been waiting for you all day.";
char ch = 'p';
cout.write(s2, strlen(s2));
cout << endl;
for (int i = 0; i < strlen(s1); i++)
{
cout.write(s1, i);
cout << endl;
}
cout.put(ch).put(ch + 1);
cout << 'o';
return 0;
}
2.4.2调整字段宽度
可以使用width成员函数将长度不同的数字放到宽度相同的字段中,所以必须使用对象来调用它,该方法的原型是:
int width();
int width(int i);
第一种格式返回字段宽度的当前设置;第二种格式将字段宽度设置为i个空格,并返回以前的字段宽度值。这使得能够保存以前的值,以便以后恢复宽度值时使用。width()方法只影响将显示的下一个项目,然后字段恢复默认值。
C++永远不会截短数据,如果试图在字段宽度为2的字段中打印字段为7的值,C++将增宽字段。
#include<iostream>
using namespace std;
int main()
{
cout << "Enter an interger:";
int n;
cin >> n;
cout << "n";
cout.width(8);
cout<<"n * n\n";
cout << n;
cout.width(8);
cout<< n * n << endl;
cout << hex;
cout << n;
cout.width(8);
cout << n * n << endl;
cout << oct;
cout << n;
cout.width(8);
cout << n * n << endl;
cout << dec;
cout << n;
cout.width(8);
cout << n * n << endl;
return 0;
}
我们可以看到,值在字段中右对齐,cout通过加入空格来填满整个字段。
2.4.3填充字符
在默认情况下,cout用空格填充字段中未被使用的部分,可以用fill()成员函数来改变填充字符。下面的函数调用将填充字符改为星号:
cout.fill('*');
新的填充字符将一直有效,直到更改它为止。
#include<iostream>
using namespace std;
int main()
{
cout << "Enter an interger:";
int n;
cin >> n;
cout.fill('-');
cout << "n";
cout.width(8);
cout<<"n*n"<<endl;
cout << n;
cout.width(8);
cout<< n * n << endl;
cout << hex;
cout << n;
cout.width(8);
cout << n * n << endl;
cout << oct;
cout << n;
cout.width(8);
cout << n * n << endl;
cout << dec;
cout << n;
cout.width(8);
cout << n * n << endl;
return 0;
}
2.4.4设置浮点数的显示精度
浮点数精度的含义取决于输出模式。在默认情况下,它指的是显示的总位数。在定点模式和科学模式下,精度指的是小数点后面的位数。C++默认的精度为6位(末尾的0不显示)。precision成员函数使得能够选择其他值。下面语句将cout的精度设置为2:
cout.precision(2);
新的精度设置将一直有效,直到被重新设置。
#include<iostream>
using namespace std;
int main()
{
float price1 = 20.40;
float price2 = 1.9 + 8.0 / 9.0;
cout << "$1:" << price1 << endl; //这里的0不显示
cout << "$2:" << price2<< endl;
cout.precision(2);
cout << "$1:" << price1 << endl;
cout << "$2:" << price2 << endl;
return 0;
}
2.4.5打印末尾的0和小数点
iostream系列类没有提供专门用于完成这项任务的函数,但ios_base类提供了一个set()函数,能够控制多种格式化特性。下面的函数调用使cout显示末尾小数点:
cout.setf(ios_base::showpoint);
使用默认的浮点格式,上述语句将导致末尾的0被显示出来。如果使用默认精度(6位)时,cout将不会将2.0显示为2.0,而是显示2.00000.
ios_base::showpoint;showpoint是ios_base类声明中定义的类级静态变量。
#include<iostream>
using namespace std;
int main()
{
float price1 = 20.40;
float price2 = 1.9 + 8.0 / 9.0;
cout.setf(ios_base::showpoint);
cout << "$1:" << price1 << endl; //这里的0不显示
cout << "$2:" << price2<< endl;
cout.precision(2);
cout << "$1:" << price1 << endl;
cout << "$2:" << price2 <<