2.5 数据输入与输出
在用户与计算机进行交互的过程中,数据输入与输出是必不可少的操作过程。计算机需要通过输入获取用户的操作指令,并通过输出显示操作结果。本节将介绍数据输入与输出的相关内容。
2.5.1 控制台屏幕
在NT内核的Windows操作系统中为保留DOS系统的风格,提供了控制台程序,单击系统的“开始”→“运行”命令,运行cmd.exe程序,可以启动控制台。在控制台中可以运行DIR、CD、DELETE等DOS系统中的文件操作命令,也可以启动Windows程序。控制台屏幕如图2.7所示。
使用Visual C++ 6.0创建的控制台程序都将运算结果输出到如图2.7所示的控制台屏幕上,它是程序显示输出结果的地方。
图2.7 控制台屏幕
2.5.2 C++语言中的流
在C++语言中,数据的输入和输出发生在标准输入/输出设备(键盘、显示器)、外部存储介质(磁盘)和内存的存储空间。对标准输入/输出设备的输入/输出简称标准I/O,对在外存磁盘上文件的输入/输出简称文件I/O,对内存中指定的字符串存储空间的输入/输出简称串I/O。
C++语言中把数据之间的传输操作称为流。C++中的流既可以表示数据从内存传送到某个载体或设备中,即输出流;也可以表示数据从某个载体或设备传送到内存缓冲区变量中,即输入流。C++中所有流都是相同的,但文件可以不同(文件流参见第16章)。使用流以后,程序用流统一对各种计算机设备和文件进行操作,使程序与设备、文件无关,从而提高了程序设计的通用性和灵活性。
C++语言定义了I/O类库供用户使用,标准I/O操作有4个类对象,分别是cin、cout、cerr和clog。其中cin代表标准输入设备键盘,也称cin流或标准输入流。cout代表标准输出显示器,也称cout流或标准输出流,当进行键盘输入操作时使用cin流,当进行显示器输出操作时使用cout流,当进行错误信息输出操作时使用cerr流或clog流。
C++的流通过重载运算符“<<”和“>>”执行输入和输出操作。输出操作是向流中插入一个字符序列,因此,在流操作中,将左移运算符“<<”称为插入运算符。输入操作是从流中提取一个字符序列,因此,将右移运算符“>>”称为提取运算符。
1.cout语句的一般格式
cout<<表达式1<<表达式2<<…<<表达式n;
cout代表显示器,执行cout << x操作就相当于把x的值输出到显示器。
先把x的值输出到显示器屏幕上,在当前屏幕光标位置显示出来,然后cout流恢复到等待输出的状态,以便继续通过插入操作符输出下一个值。当使用插入操作符向一个流输出一个值后,再输出下一个值时将被放在上一个值的后面,所以为了让流中前后两个值分开,可以在输出一个值后接着输出一个空格,或一个换行符,或其他需要的字符或字符串。
一个cout语句可以分写成若干行,例如:
cout<< "Hello World!" <<endl;
可以写成:
也可写成多个cout语句:
以上3种情况的输出均正确。
2.cin语句的一般格式
cin>>变量1>>变量2>>…>>变量n;
cin代表键盘,执行cin>>x操作就相当于把键盘输入的数据赋值给变量。
当从键盘上输入数据时,只有当输入完数据并按下Enter键后,系统才把该行数据存入键盘缓冲区,供cin流顺序读取给变量。另外,从键盘上输入的每个数据之间必须用空格或Enter键分开,因为cin为一个变量读入数据时是以空格或Enter键作为其结束标志的。
当cin>>x操作中的x为字符指针类型时,则要求从键盘的输入中读取一个字符串,并把它赋值给x指向的存储空间,若x没有事先指向一个允许写入信息的存储空间,则无法完成输入操作。另外,从键盘上输入的字符串,其两边不能带有双引号定界符,若有则只作为双引号字符看待。对于输入的字符也是如此,不能带有单引号定界符。
cin相当于C库函数中的scanf,作用是将用户的输入赋值给变量。例如,下面的代码可将用户输入的数打印出来。
【实例2.3】 默写王之涣的《登鹳雀楼》。(实例位置:资源包\TM\sl\2\3)
使用cout向控制台输出唐朝诗人王之涣的《登鹳雀楼》,具体代码如下:
运行程序,将向控制台屏幕输出诗句,效果如图2.8所示。其中,endl用于向流的末尾部位加入换行符。
2.5.3 流操作的控制
图2.8 向控制台屏幕输出诗句
在头文件iomanip.h中定义了一些控制流输出格式的函数,默认情况下整型数按十进制形式输出,也可以通过hex将其设置为十六进制输出。
(1)long setf(long f); 根据参数f设置相应的格式标志,返回此前的设置。该参数f对应的实参为无名枚举类型中的枚举常量(又称格式化常量),可以同时使用一个或多个常量,每两个常量之间要用按位或操作符连接。如需要左对齐输出,并使数值中的字母大写,则调用该函数的实参为ios::left|ios::uppercase。
(2)long unsetf(long f); 根据参数f清除相应的格式标志,返回此前的设置。如果要清除此前的左对齐输出设置,恢复默认的右对齐输出设置,则调用该函数的实参为ios::left。
(3)int width(); 返回当前的输出域宽。若返回数值为0,则表明没有为刚才输出的数值设置输出域宽。输出域宽是指输出的值在流中占有的字节数。
(4)int width(int w); 设置下一个数据值的输出域宽为w,返回为输出上一个数据值规定的域宽,若无规定则返回0。注意,此设置不是一直有效,而只是对下一个输出数据有效。
(5)setiosflags(long f); 设置f对应的格式标志,功能与setf(long f)成员函数相同,当然,在输出该操作符后返回的是一个输出流。如果采用标准输出流cout输出,则返回cout。输出每个操作符后都是如此,即返回输出它的流,以便向流中继续插入下一个数据。
(6)resetiosflags(long f); 清除f对应的格式标志,功能与unsetf(long f)成员函数相同。输出后返回一个流。
(7)setfill(char c); 设置填充字符的ASCII码为c的字符。
(8)setprecision(int n); 设置浮点数的输出精度为n。
(9)setw(int w); 设置下一个数据的输出域宽为w。
数据输入/输出的格式控制还有更简便的形式,就是使用头文件iomainip.h中提供的操作符。使用这些操作符不需要调用成员函数,只要把它们作为插入操作符“<<”的输出对象即可。
dec:转换为按十进制输出整数,是默认的输出格式。
oct:转换为按八进制输出整数。
hex:转换为按十六进制输出整数。
ws:从输出流中读取空白字符。
endl:输出换行符\n并刷新流。
ends:输出一个空字符\0。
flush:只刷新一个输出流。
【实例2.4】 控制打印格式。(实例位置:资源包\TM\sl\2\4)
本实例中,定义一个双精度类型的变量并赋值,利用各种格式打印数据,具体代码如下:
程序运行结果如图2.9所示。
【实例2.5】 变幻莫测的整数。(实例位置:资源包\TM\sl\2\5)
本实例中,定义一个整数变量并赋值,利用不同形式输出整型,具体代码如下:
程序运行结果如图2.10所示。
图2.9 控制打印格式
图2.10 整数输出
【实例2.6】 十六进制与十进制转换。(实例位置:资源包\TM\sl\2\6)
本实例中,定义两个整型变量,其中一个变量赋值为十六进制,另一个变量赋值为十进制。利用cout输出第一个变量十进制、十六进制,用cout输出第二个变量小写十六进制和大写十六进制。具体代码如下:
程序运行结果如图2.11所示。
【实例2.7】 控制输出精确度。(实例位置:资源包\TM\sl\2\7)
本实例中,定义一个整型变量并赋值,定义一个双精度变量并赋值,利用cout输出这两个不同精度的格式,具体代码如下:
程序运行结果如图2.12所示。
图2.11 输出十进制和十六进制
图2.12 控制输出精确度
【实例2.8】 千变万化的小数。(实例位置:资源包\TM\sl\2\8)
本实例中,定义两个单精度类型,用cout输出不同长度的小数,具体代码如下:
程序运行结果如图2.13所示。
C++语言中还保留着C语言的输出函数printf,使用printf可以将任意数量、类型的数据输出到屏幕中。printf函数的声明形式如下:
printf("[控制格式]... [控制格式]...",数值列表);
printf是变参函数,数值列表中可以有多个数值,数值的个数不是确定的,每个数值之间用逗号运算符隔开;控制格式表示数值以哪种格式输出,控制格式的数量要与数值的个数一致,否则程序运行时会产生错误。
控制格式由“%+特定字符”构成,形式如下:
%[*][域宽][长度]类型
“*”代表可以使用占位符,域宽表示输出的长度。如果输出的内容没有域宽长,用占位符占位;如果比域宽长,就按实际内容输出,以适应域宽。长度决定输出内容的长度,例如,%d代表以整型数据格式输出。常见的输出类型如表2.6所示。
表2.6 常见输出类型
(1)d格式符,以十进制形式输出整数。
%d:按整型数据的实际长度输出。
%*md:m用于指定输出字段的宽度,如果数据的位数小于m,用*指定的字符占位;如果*未指定用空格占位,若大于m,则按实际位数输出。
%ld:输出长整型数据。
【实例2.9】 printf占位输出形式。(实例位置:资源包\TM\sl\2\9)
本实例中,使用printf格式输出函数,在格式符号中间加0做占位符,具体代码如下:
程序运行结果如图2.14所示。
图2.13 流输出小数控制
图2.14 输出占位符
(2)o格式符,以八进制形式输出整数。
%o:按整型数据的实际长度输出。
%*mo:m用于指定输出字段的宽度,如果数据的位数小于m,用*指定的字符占位;如果*未指定用空格占位,若大于m,则按实际位数输出。
%lo:输出长整型数据。
(3)x格式符,以十六进制形式输出整数。
%x:按整型数据的实际长度输出。
%*mx:m用于指定输出字段的宽度,如果数据的位数小于m,用*指定的字符占位;如果*未指定用空格占位,若大于m,则按实际位数输出。
%lx:输出长整型数据。
(4)s格式符,用来输出一个字符串。
%s:将字符串按实际长度输出。
%*ms:输出的字符串占m列,如果字符串本身长度大于m,则突破m的限制,将字符串全部输出;如果*未指定用空格占位,若字符串长度小于m,则左补空格。
%-ms:如果字符串长度小于m,则在m列范围内,字符串向左靠,右补空格。
%m.ns:输出占m列,但只取字符串中左端n个字符。这n个字符输出在m列的右侧,左补空格。
%-m.ns:输出长整型数据。输出占m列,但只取字符串中左端n个字符。这n个字符输出在m列的左侧,右补空格。
【实例2.10】 截取helloworld。(实例位置:资源包\TM\sl\2\10)
本实例中,定义字符型指针(第7章详细介绍)用来保存字符串,利用printf函数格式输出字符串,代码如下:
程序运行结果如图2.15所示。
(5)f格式符,以小数形式输出实型数据。
%f:不指定字段宽度,整数部分全部输出,小数部分输出6位。
%m.nf:输出的数据占m列,其中有n位小数。如果数值长度小于m,则左端补空格。
%-m.nf:输出的数据占m列,其中有n位小数。如果数值长度小于m,则右端补空格。
【实例2.11】 输出格式控制。(实例位置:资源包\TM\sl\2\11)
本实例中,定义一个单精度和一个双精度类型,利用printf格式输出不同形式,具体代码如下:
程序运行结果如图2.16所示。
图2.15 输出格式控制字符串输出
图2.16 输出格式控制
(6)e格式符,以指数形式输出实型数据。
%e:不指定输出数据所占的宽度和小数位数。
%m.ne:输出的数据占m位,其中有n位小数。如果数值长度小于m,则左端补空格。
%-m.ne:输出的数据占m位,其中有n位小数。如果数值长度小于m,则右端补空格。
【实例2.12】 科学计数法输出。(实例位置:资源包\TM\sl\2\12)
本实例中,利用printf格式控制符%e,将小数用科学计数法输出,具体代码如下:
程序运行结果如图2.17所示。
图2.17 科学计数法输出
误区警示
一定要注意%x(%X、%#x、%#X),因为调试时经常要将内存中的二进制代码输出。这几种形式解释如下:
如果是x,输出的字母就是小写的;如果是X,输出的字母就是大写的;如果加一个“#”就会以标准的十六进制形式输出。建议最好是加一个“#”,否则如果输出的十六进制正好没有字母,就会被误认为是一个十进制数。
编程训练(答案位置:资源包\TM\sl\2\编程训练\)
【训练3】 控制台输出汉字 使用cout向控制台输出汉字“明日科技”。
【训练4】 地球的年龄有多大 地球的年龄约为45.5亿年,用科学计数法输出地球的年龄。