本节书摘来自华章出版社《C++程序设计教程(第3版)》一书中的第3章,第3.2节cout输出流,作者张志航,更多章节内容可以访问云栖社区“华章计算机”公众号查看
3.2 cout输出流
计算机的输入输出分为两大类:标准输入输出和文件输入输出。键盘是计算机的默认标准输入设备,显示器是计算机的默认标准输出设备,所以在键盘和显示器上的输入输出称为标准输入输出。数据在磁盘上是以文件为单位存放的,所以磁盘数据的输入输出称为文件输入输出。由于在一个系统中,键盘和显示器一般都只有一个,从键盘获取数据,将结果显示到显示器上,所以操作起来比较简单。而在磁盘访问中,往往需要同时对多个文件进行操作,所以操作起来比较复杂。本章是C++学习的基础,所以只讨论简单的标准输入输出的操作方法。
C++中没有专门的输入输出语句,所有的输入输出操作都是通过输入输出流来实现的。在输入输出流中,输入操作是通过流对象cin来实现的,而输出操作是通过流对象cout来实现的。cin是由c和in两个单词组成的,代表C++的输入流;cout是由c和out两个单词组成的,代表C++的输出流。
由于cin和cout都是在头文件iostream中定义的,前面我们提到过,C++中任何系统提供的操作或者函数的使用都需要加入对应的头文件说明。因此,要使用C++提供的输入输出流技术时,必须在程序的开头增加两行说明,如下:
`include
using namespace std;`
即在程序中首先包含输入输出流的头文件iostream,同时说明C++标准程序库被定义于一个名为std的namespace中。关于包含文件的作用,在第6章将进行详细介绍。下面举例说明如何使用输入输出流技术来实现与例3.1完全相同的功能。
例3.2 演示基本的C++输入输出流的使用方法。
`include
using namespace std;
int main()
{
char a;
cout << "Please input a character:";
cin >> a; //输入数据到a变量
cout << "The character is: " << a << endl;
return 0;
}`
从上面的例子可以看出,使用输入输出流时不再需要对输入和输出的变量类型加以说明,系统会自动识别,这一点是利用面向对象的重载技术实现的,是对传统的输入输出函数的重大改进。下面我们来具体介绍输出流的基本使用方法。
使用cout输出流可以方便地将内存中的数据显示给用户查看。根据本章开始的介绍,在程序中输出功能的重要性还要大于输入功能,任何一个有实际用途的程序至少要有一个输出来显示计算结果。因此,在本节中将花较多的篇幅来介绍把字符、整数、实数及字符串等不同类型数据输出到显示器的基本方法。同样,有关输出流对象cout所能实现的详细功能,将在第14章中进行介绍。
在程序执行期间,我们使用cout将变量中的数据或者字符串输出到屏幕上或者文件中,以便用户查看。其一般格式为:
cout << <表达式1> [ << <表达式2> << … << <表达式n> ]
其中,运算符“<<”用来将内存中的数据插入cout数据流中,然后输出到标准输出设备显示器上。在C++中这种输出操作称为“插入”(Inserting),因此运算符“<<”也称为插入运算符,它将紧跟其后的表达式的值插入cout数据流中,输出到显示器当前光标的位置。程序执行中如果遇到插入运算符,则将内存变量的值输出,然后程序继续向下运行。
输出流的使用方法记忆起来也非常简单,可以将cout想象成显示器,插入运算符“<<”想象成指向箭头。由于“箭头”是从内存变量“指向”cout的,因此代表了将内存变量中的数据插入输出设备中。
在C++中,运算符“<<”具有多种功能,它除了可以做输出流的插入运算符之外,还可以作为位运算的左移运算符来使用。但是,当它和cout关键字连用的时候,它只能作为插入运算符来使用。这种同一个符号具有不同的使用含义的特性是C++对传统的C语言的一种重要扩充,利用了面向对象编程技术中的运算符重载技术,具体的细节将在本书后面的有关运算符重载部分加以详细说明。
根据上面的格式说明,在每个插入运算符后面可以跟一个表达式。在显示数据时可以将变量值和字符串融合在一起,构造出直观的答案。这样,cout输出流在使用中的变化就要比cin输入流来得复杂,能够实现的功能也要强大一些。同样,“<< <表达式>”的组合可以重复多次,即在cout后面使用一次“<< <表达式>”可以输出一个表达式的值,在cout后边重复使用多次“<< <表达式>”可以一次输出多个表达式的值,并且可以将多个变量的值与多个字符串组合在一起,构成复杂的输出结果,如例3.3所示。
例3.3 演示使用输出流技术的问答式程序。
`include
using namespace std;
int main()
{
int i;
cout << "请输入变量i的值:";
cin >> i; //输入数据到i变量
cout << "您输入的数值是:" << i <<endl ;
return 0;
}`
在执行第一条cout语句时,在显示器上显示:
请输入变量i的值:
即cout将双引号中的字符串常量按其原样输出。接着执行cin语句,屏幕上的光标停留在冒号的后面,等待用户输入变量i的值。通常在程序设计中,在每一个cin语句之前,都会用一个cout语句给出提示信息,指明用户给什么变量输入数据,并且以什么样的数制输入。这样用户面对的不再是孤零零的黑色屏幕,而是针对每一个提示输入相关的数据,能够降低出错的概率。这种程序的编制方法称为问答式程序界面。
下面再举例说明输出流cout对多变量的处理方法,如例3.4所示。
例3.4 演示使用输出流技术的多变量输出。
`include
using namespace std;
int main()
{
int a=10, b=20, c=30, d=40;
double m=5.23, n=100;
cout << a << b << endl;
cout << c << n-d << endl;
cout << m << n << endl;
return 0;
}`
输出结果为:
1020
3060
5.23100
以上每一个cout语句输出一行,其中endl表示要输出一个换行符,它是短语“end of line”的缩写,它等同于转义字符'n'。当用cout输出多个数据时,缺省情况下,是按每一个数据的实际长度输出的,即在每一个输出的数据之间不会自动加入分隔符。显然,如果直接输出数据,所有的数据将连接在一起,无法分清哪一个变量的输出值是多少。如第一行输出1020,实际上是先输出a的值10,再输出b的值20。为了区分输出的数据项,在每一个输出数据之间要输出分隔符。分隔符可以是空格、标点符号或者换行符等。如上面的输出语句可改写为:
`cout << a << ',' << b<< endl;
cout << c << ',' << n-d << endl;
cout << m << ',' << n << endl;`
则输出结果为:
`10, 20
30, 60
5.23, 100`
还可以改写成:
`cout <<"a=" << a << 't' <<"b=" << b << endl;
cout <<"c=" << c << 't' << n << "-" << d <<"=" << n-d << endl;
cout <<"m=" << m << 't' <<"n="<< n << endl;`
则执行这3个输出语句后,输出:
a=10 b=20
c=30 100-40=60
m=5.23 n=100
从上面的例子可以看出,在cout中输出数据的格式并不是根据变量的类型确定的。例如,变量y是双精度浮点数类型,按道理应该输出一个小数格式的数据,但是输出的数据却是一个整数100。在输出流cout中是根据变量的数值而不是根据变量的数据类型来决定输出数据的格式的。同时,我们还要看到,一个清晰的输出结果往往是由字符串、控制字符和变量值共同组成的。所以在使用输出流cout时,一定要综合使用多种控制技术,以便用户能够从输出结果中轻松地获得需要的信息。
使输出的数据项之间隔开的另一种办法是使用setw()函数来指定输出数据项的宽度。例如上面的3个输出语句可以改写为:
`cout << setw(10) << a << setw(10) << b << endl;
cout << setw(10) << c << setw(10) << n-d << endl;
cout << setw(10) << m << setw(10) << n << endl;`
其中,setw(10)指明其后的输出项占用的字符宽度为10,即括号中的值指出紧跟其后的输出项占用的字符位置个数,并且给定宽度大于实际数据位数时默认向右对齐,左侧填充空格,填满给定的宽度。setw是“set width”的缩写。执行以上3个语句后的输出为:
10 20
30 60
5.23 100
使用setw()函数应该注意以下4点。
1)setw()函数是定义在iomanip头文件中的系统函数,所以要使用它就必须在程序的开始位置包含头文件iomanip,即在程序的开头增加:
include
using namespace std;
2)括号中必须给出一个正整数或者数学表达式(值为正整数),它指明紧跟其后输出的数据项的宽度。
3)该设置仅对其后的一个输出项有效。一旦按指定的宽度输出其后的输出项后,程序又自动回到原来的按实际宽度输出的缺省输出方式。
4)当设置了数据的输出宽度后,如果数据的实际位数小于指定的宽度,则添加填充符(默认填充符为空格,且右对齐、左边补空格)。如果数据的实际位数大于指定的宽度,则数据按照实际的宽度输出,不会按照指定的宽度来截断数据。
上面介绍了输出流对象cout对于数据的通用处理方法。在cout中除了基本操作方法以外,还针对不同的数据设计了一些特殊的处理方法。下面分别按照数值型数据和字符型数据来对这些处理方法进行分类介绍。
3.2.1 输出八进制数、十六进制数和用科学记数法表示的数
在cout中对于整型数据可以指定以十六进制或八进制输出。对于实型数据可以指定以小数形式或者科学记数法形式输出,如例3.5所示。
例3.5 演示使用输出流技术按照特定的格式输出数值数据。
`include
using namespace std;
int main()
{
int a=10, b=20, c=30, d=40;
double m=5.23, n=100;
cout << "a=" << oct << a << '\t' << "b=" << b << endl;
cout.setf(ios::scientific, ios::floatfield); //按照科学记数法输出实数
cout << "c=" << hex << c << '\t' << "n-d=" << n-d << endl;
cout << "m=" << m << endl;
cout.unsetf(ios::scientific); //取消按照科学记数法输出
cout << "m=" << m << '\t' << "n=" << n << endl;
return 0;
}`
执行该程序后,输出:
`a=12 b=24
c=1e n-d=6.000000e+001
m=5.230000e+000
m=5.23 n=100`
在程序中,hex和oct这两个标识符用在输出流cout中,分别代表了程序应该按照十六进制和八进制格式输出数据。一旦在cout语句中指定了输出的进制格式后,这种格式将一直有效,直到指定另外一种进制格式为止。
在程序中调用了两个系统函数:cout.setf()和cout.unsetf()。其中,cout.setf()函数用来设置标志位ios::scientific,指定对实数按照科学记数法格式输出,而cout.unsetf()用来取消标志位设置,终止对实数按照科学记数法格式输出。与整数的特定进制格式输出相同,一旦指定了按照科学记数法输出实数,其后所有的实数都将按照科学记数法的格式输出,直到取消科学记数法的输出格式为止。关于cout.setf()函数和cout.unsetf()函数的使用原理,我们将在第14章中进行介绍。
在例3.5输出的结果中,由于指定了按照八进制格式输出变量a和b的值,因此将十进制数10输出成八进制数12,将十进制数20输出成八进制数24。随后指定将实数按照科学记数法格式输出,由于变量c是整数,因此将十进制数30按照十六进制格式输出成1e。由于变量n是实数,所以计算结果也是实数,按照科学记数法格式输出成6.000 000 e+001。随后,按照科学记数法格式输出变量m的值为5.230 000 e+000。取消了科学记数法格式,恢复了小数格式以后,输出变量m和n的值分别为5.23和100。
3.2.2 输出字符或字符串
输出流对象cout除了能够输出正常可视的标准字符外,还可以输出一些不可见的控制字符,这些字符就是第2章中所说的转义字符。如下面的程序片段所示:
`char c='a',c1='b';
cout << "c=" << c << 't' << "c1=" << c1 << 'n';`
执行cout语句时,先输出“c=”可视的标准字符串;接着输出变量c的值;再输出不可视的“横向制表符”控制字符,跳到下一个Tab位置;再输出“c1=”可视的标准字符串;接着输出变量c1的值;最后输出一个不可视的“换行符”控制字符,表示以后的输出从下一行开始。所以该行的输出结果为:
c=a c1=b
在计算机字符界面中,一屏显示界面可以显示80×25个字符,即一屏显示25行字符,每行最多80个字符。将屏幕位置按照8列为一个单位进行划分,整个屏幕可以划分为10个单位,每个单位就是我们所说的一个Tab位置。当用户按下键盘上的Tab键时,光标会从当前的8列区间移动到下一个8列区间的第1列的位置。例如,当前光标处于屏幕的第3列属于第一个区间,按下Tab键,光标会移动到第9列,即第二个区间的第1列。如果光标处于第7列,因为同样属于第一个区间,按下Tab键,光标还是会移动到第9列。同样的道理,如果光标处于第12列,则按下Tab键,会移动到第17列。以此类推,可以很容易地计算出输出内容之间的间隔。例如,在上面的例子中两个输出变量之间的间隔为5个字符。
根据上例所示,使用第2章介绍的转义字符的书写方法,用cout可以输出任何ASCII码的字符。