- C++面向对象程序设计
- 杜茂康等编著
- 1986字
- 2020-08-28 09:47:01
1.5 数据输入与输出
程序执行的基本逻辑是:输入数据 → 处理数据 → 输出结果。数据的输入/输出几乎是每个程序不可避免的问题。
1.5.1 流的概念
在C++中,I/O(Input/Output,输入/输出)数据是一些从源设备到目标设备的字节序列,称为字节流。除了图像、声音数据外,字节流通常代表的都是字符,因此,在多数情况下的流(stream)都是从源设备到目标设备的字符序列,如图1-5所示。
图1-5 流示意图
流分为输入流和输出流两类。输入流(input stream)是指从输入设备流向内存的字节序列。例如,在图1-5中,若源设备是键盘,目标设备是内存,则表示的是输入流,表示通过键盘输入数据到内存变量中。输出流(output stream)是指从内存流向输出设备的字节序列。例如,在图1-5中,若源设备是内存,目标设备是显示器,就是输出流,表示把内存中的字符逐个输出到显示屏幕上。
在C++中,标准输入设备通常是指键盘,标准输出设备通常是指显示器。为了从键盘输入数据,或为了将数据输出到显示器屏幕上,程序中必须包含头文件iostream.h。这个头文件包括了输入流istream和输出流ostream两种数据类型,而且用这两种数据类型定义了两个变量“istream cin”和“ostream cout”。其中,cin(读作see-in)用于从键盘输入数据,cout(读作see-out)用于将内存数据输出到显示器。
1.5.2 cin和析取运算符>>
在C++程序中,常用cin输入数据。其用法如下:
cin>>x;
程序执行到cin语句时,就会停下来等待键盘数据的输入,输入数据被插入到输入流中,数据输完后按Enter键结束。当遇到运算符>>时,就从输入流中提取一个数据,存入内存变量x中。
① cin是在iostream.h中预定义的一个标准输入设备(一般代表键盘),>>是析取运算符,用于从输入流中析取数据(即从流中分析和提取数据),并存于其后的变量x中。x是程序中定义的变量名,原则上x应该是系统内置的简单数据类型,如int、char、double等。
② 在一条cin语句中可以同时为多个变量输入数据。在输入数据时应当输入与cin语句中变量个数相同的数据,各输入数据之间用一个或多个空白(包括空格、回车、Tab)作为间隔符,全部数据输入完成后,按Enter键结束。例如,下面的程序段:
int x1; double x2; char x3; cin>>x1>>x2>>x3;
假设x1为5,x2为3.4,x3为'A',则下面的两种输入方式等效:
5 3.4 A
或
5 3.4 A
当一条cin语句中有多个运算符>>时,就需要从键盘输入多个数据到输入流中,每当遇到一个>>时,就从输入流中提取一个数据存入其后的变量中。
可以把一条cin语句分解为多条cin语句,也可以把多条cin语句合并为一条语句,所以上面的输入语句与下面的语句组等效:
cin>>x1; cin>>x2; cin>>x3;
③ 在>>后面只能出现变量名,这些变量应该是系统预定义的简单类型,否则将出现错误。下面的语句是错误的:
cin>>"x=">>x; //错误,>>后面含有字符串"x=" cin>>12>>x; //错误,>>后面含有常数12 cin>>'x'>>x; //错误,>>后面含有字符'x'
④ cin具有自动识别数据类型的能力,析取运算符>>将根据其后变量的类型从输入流中为它们提取对应的数据。例如:
cin>>x;
假设输入数据2,析取运算符>>将根据其后的x的类型决定输入的2到底是数字还是字符。若x是char类型,则2就是字符;若x是int,float之类的类型,则2就是一个数字。
再如,若输入34,且x是char类型,则只有字符3被存储到x中,4将继续保存在流中;若x是int或float,则34就会存储到x中。
⑤ 数值型数据的输入。在读取数值型数据时,析取运算符>>首先略掉数据前面的所有空白符号,如果遇到正、负号或数字,就开始读入,包括浮点型数据的小数点,并在遇到空白符或其他非数字字符时停止。例如:
int x1; double x2; char x3; cin>>x1>>x2>>x3;
假如输入“35.4A”并按Enter键,第1个析取运算符>>根据x1的类型int,从输入流中提取一个整数存储在x1中,这个整数只能是35。因为接下来的是“.”不是整数的有效数字,所以提取x1后,输入流中的数据是“.4A”。第2个析取运算符>>将从输入流中为x2提取数据,x2是double型,所以只能把“.4”存储到x2中,因为接在4后面的A不是有效的数字,所以x2的结果为0.4(0由系统产生);第3个析取运算符>>为x3提取数据,x3是char型,所以字符'A'就被输入到x3中。
这个结果或许不正确,却从另一方面说明了在输入数据时,一定要注意数据之间间隔符的正确输入。结合上述各种情况,来看一个数据输入的综合性例子。
【例1-2】 假设有变量定义语句如下:
int a,b; double z; char ch;
下面的语句说明数据输入的含义。
语句 输入 内存变量的值
1 cin>>ch; A ch='A' 2 cin>>ch; AB ch='A',而'B'被保留在输入流中等待被读取 3 cin>>a; 32 a=32 4 cin>>a; 32.23 a=32,后面的.23被保留在输入流中等待被读取 5 cin>>z; 76.21 z=76.21 6 cin>>z; 65 z=65.0 7 cin>>a>>ch>>z 23 B 3.2 a=23,ch='B',Z=3.2 8 cin>>a>>ch>>z 23B3.2 a=23,ch='B',Z=3.2 9 cin>>a>>b>>z 23 32 a=23,b=32,计算机等待输入下一个数据存入z 10 cin>>a>>z 2 3.2 24 a=2,z=3.2,而24被保留在输入流中等待被读取 11 cin>>a>>ch 132 a=132,计算机等待输入 ch的值 12 cin>>ch>>a 132 ch='1',a=32
1.5.3 cout和插入运算符<<
在C++程序中,一般用cout输出数据,其用法如下:
cout<<x;
程序执行到cout语句时,将在显示屏幕上把x的值显示出来。x可以是字符串、变量或常量。
cout是在iostream.h中定义的标准输出设备(一般代表显示器),<<是插入运算符,用来将其右边的x的值插入到输出流中(cout是流向的目的地,所以最终是把x显示在屏幕上)。
(1)输出字符类型的数据
字符类型数据包括字符常量、字符串常量、字符变量和字符串变量。对于字符常量和字符串常量,cout将把它们原样输出在屏幕上;对于字符变量和字符串变量,cout将把变量的值输出到显示屏幕上。例1-3是一个字符输出示例程序。
【例1-3】 用cout输出字符数据。
//Eg1-3.cpp #include<iostream.h> void main() { char ch1='c'; char ch2[]="Hellow C++!"; cout<<ch1; cout<<ch2; cout<<"C"; cout<<"Hellow everyone!"; }
程序的运行结果如下(这个结果是由程序中的4条cout语句共同输出的):
cHellow C++!CHellow everyone!
(2)连续输出
cout语句能够同时输出多个数据,其用法如下:
cout<<x1<<x2<<x3<<…;
其中,x1,x2和x3可以是相同或不同类型的数据,此命令将依次把x1、x2和x3的值输出到显示屏幕上。
cout的这种格式表明,可以把多条cout语句合并成一条语句。当然,也可以把一条cout语句分解为多条语句。将Eg1-3.cpp程序中的4条cout语句合并成一条命令,不会影响程序的功能,其运行结果完全相同:
cout<<ch1<<ch2<<"C"<<"Hellow everyone!";
与C语言一样,在C++程序中也可以将一条命令写在多行上。例如,上面的语句也可写成下面的形式:
cout<<ch1 <<ch2 <<"C" <<"Hellow everyone!";
(3)输出换行
例1-3的输出结果并不清晰,如果能够把它们输出在多行上,效果会更好。在cout语句中,可以通过输出换行符“\n”或endl操纵符将输出光标移动到下一行的开头处。例1-4是对例1-3的改写。
【例1-4】 在例1-3的输出语句中增加换行符。
//Eg1-4.cpp #include<iostream.h> void main(){ char ch1='c'; char ch2[]="Hellow C++!"; cout<<ch1<<endl; cout<<ch2<<"\n"; cout<<"C"<<endl; cout<<"Hellow everyone!\n"; }
本程序的输出如下:
c Hellow C++! C Hellow everyone!
endl和“\n”具有相同的功能,它们可以出现在cout语句中任何位置的<<的后面。“\n”还可以直接放在字符串常数的后面,如语句“cout<<"Hellow everyone!\n"”最后的“\n”。
(4)输出数值类型的数据
数值型常量数据可以利用cout直接输出,例如:
cout<<1<<2<<3<<endl;
将在屏幕上显示:123。数值变量的输出也是如此,如下面的程序段:
int x1=23; float x2=34.1; double x3=67.12; cout<<x1<<x2<<x3<<900;
其中的cout语句将在屏幕上输出“2334.167.12900”。
从上面两条输出语句的结果可以看出:cout在输出多个数据时,不会在数据之间插入任何间隔符,其结果是使输出数据变得含混不清,如数值1,2,3被输出成了123。
针对这种情况,需要在cout输出语句中添加一些数据间隔符。例如,可将上面的语句改写为:
cout<<1<<" "<<2<<" "<<3<<endl; cout<<"x1="<<x1<<" "<<"x2="<<x2<<" "<<"x3="<<x3<<endl<<900<<endl;
下面是这两条语句的输出结果,显然它比前面的输出结果更清晰。
1 2 3 x1=23 x2=34.1 x3=67.12 900
1.5.4 输出格式控制符
在程序运行过程中,常常需要按照一定的格式输出其运行结果,如设置数值精度、设置小数点的位置、设置输出数据宽度或对齐方式……数据输出格式的设置是程序设计的一个重要内容,影响到程序结果的清晰性。
C++提供了许多控制数据输入输出格式的函数和操纵符(也称为操纵函数或操纵算子),如setprecision、setw、right等,它们都是在iomanip.h中定义的,应用它们时要包含该头文件。
(1)设置浮点数的精度
在需要设置输出数据的精度时,可以用操纵函数setprecision()。其用法如下:
setprecision(n)
其中,n代表有效数位,包括整数的位数和小数的位数。如setprecision(3)将所有数值的输出精度都指定为3位有效数字,直到再次用setprecision()改变输出精度为止。setprecision()是在iomanip.h中定义的,在使用时要包含该头文件。例如,语句
cout<<setprecision(3)<<3.1415926<<" "<<2.4536<<endl;
将输出“3.14 2.45”。
(2)设置输出域宽和对齐方式
在C++中,可以用操纵函数setw()设置输出数据占用的列数(域宽,即占用的字符个数)。setw()的用法如下:
setw(n)
其中,n是输出数据占用屏幕宽度的字符个数,在默认情况下,输出数据按右对齐。若输出数据的位数比n小,则左边留空。若输出数据的实际位数比n大,则输出数据将自动扩展到所需占用的列数。例如:
cout<<"1234567812345678"<<endl; //L1 cout<<setw(8)<<23.27<<setw(8)<<78<<endl; //L2 cout<<setw(8)<<"Abc"<<78<<endl; //L3
上述语句的输出结果如下:
1234567812345678 23.27 78 Abc78
setw()只对紧随其后的一个输出数据有效,语句L3中的setw(8)只对跟在其后的字符串"Abc"有效,所以最后的“78”就按默认方式输出,紧接在"Abc"的后边。
(3)设置对齐方式
操纵函数setiosflags()和resetiosflags()可用于设置或取消输入/输出数据的各种格式,包括改变数制基数、设置浮点数的精度、转换字母大小写、设置对齐方式等。它们的用法如下:
setiosflags(long f); resetiosflags(long f);
在iostream.h中还定义了两个表示对齐方式的常数,表示左对齐的常数值是ios::left,表示右对齐的常数值是ios::right,它们可作为setiosflags( )和resetiosflags( )操纵符的参数,用于设置输出数据的对齐方式。
在默认方式下,C++按右对齐方式输出数据。当用setiosflags()设置输出对齐方式成功后,将一直有效,直到用resetiosflags()取消它。
【例1-5】 用setiosflags()和resetiosflags()设置和取消输出数据的对齐方式。
//Eg1-5.cpp #include<iostream.h> //L1 #include<iomanip.h> //L2 void main(){ //L3 cout<<"123456781234567812345678"<<endl; //L4 cout<<setiosflags(ios::left)<<setw(8)<<456<<setw(8)<<123<<endl; //L5 cout<<resetiosflags(ios::left)<<setw(8)<<123<<endl; //L6 }
这个程序的输出结果如下:
123456781234567812345678 456 123 123
输出结果的第1行是语句行L4输出的;第2行是语句行L5输出的,输出的两个数据各占8位,且设置了左对齐方式;第3行是语句行L6的输出,输出数据占8位,由于在输出之前用resetiosflags(ios::left)操纵符取消了左对齐,使数据输出又成了默认的右对齐方式,所以输出数据的左边留了5个空白。
1.5.5 数制基数
C++在iostream.h中预定义了hex、oct、dec等操纵符。分别表示十六进制数、八进制数和十进制数。在默认方式下,C++按照十进制数形式输入、输出数据。当要按其他进制输入、输出数据时,就需要在cin和cout语句中指定数据的基数。在用键盘输入数据时:
十进制整数:直接输入数据本身,如78。
十六进整数:在要输入的数据前加0x或0X,如0x1A(对应的十进制数是26)。
八进制整数:在输入的数据前加0,如043(代表十进制数35)。
【例1-6】 输入、输出不同进制的数据。
//Eg1-6.cpp #include<iostream.h> void main(){ int x=34; cout<<hex<<17 <<" "<<x<<" "<<18<<endl; cout<<17 <<" "<<oct <<x<<" "<<18<<endl; cout<<dec<<17 <<" "<<x<<" "<<18<<endl; int x1, x2, x3, x4; cout<<"输入 x1(oct), x2(oct), x3(hex), x4(dec):"<<endl; cin>>oct>>x1; //八进制数 cin>>x2; //八进制数 cin>>hex>>x3; //输入十六进制数 cin>>dec>>x4; //输入十进制数 cout<<"x1="<<x1<<"\tx2="<<x2<<"\tx3="<<x3<<"\tx4="<<x4<<endl; }
设置数制基数后,它将一直有效,直到遇到下一个基数设置。本程序运行结果如图1-6所示。
图1-6 程序运行结果
其中,第1行和第2行的11是十六进制数,第2行的42和22是八进制数,第3行是十进制数。第5行是从键盘输入的数据,013、034是八进制数,0x2a是十六进制数,18是十进制数。最后一行是按十进制输出的数据。