输入输出初步(C++)

1. 标准输入/输出

1.1 标准设备

1.1.1 概念

单纯在控制台窗口运行的C/C++程序,需要通过窗口进行输入/输出。C/C++通过一些列的函数从键盘获取按键信息,或者将数据信息传送到窗口显示。

C/C++把键盘设备默认为标准输入设备,把控制台窗口默认为标准输出设备。意即一运行程序,只要与输入/输出设备打交道,便默认地与键盘和控制台窗口发生联系。标准设备有一些标准的操作,只要其他设备指定为标准设备,则都可以使用这些标准的操作来进行输入/输出。

1.1.2 操作

C语言的标准设备中的标准操作由一组函数规定,其中典型的有scanf与printf,putchar与puts,getchar与gets等。除此之外,还有专门针对控制台设备的putch,getch等操作。

1.1.3 内部硬件驱动

要操作标准设备,必将根据程序代码的指定去驱动特定的设备。如果是针对特定设备的操作,例如专门针对控制台的操作,则可以省去设备选择的步骤。

1.1.4 流概念主导

标准设备的标准操作的关键是将设备看做是一个字符流,内中含有诸多可见与不可见的字符,通过识别流中特定的符号来控制操作的结束。例如,读取一行字串,可以按序取一些字符,直至遇到回车符;读取一个字串,可以按序取一些字符,直至遇到整数0(表示字串结束)。

1.1.5 流结构原理

标准设备的流特性,表现为一个一定容量的储流罐,即输入或输出缓冲区。对于输入缓冲区来说,它一边被程序所读,一边按需去取设备中的字符数据,对于输出流来说,它一边被程序所写,即接受程序传过来要求输出的内容,一边按需去写设备。所谓按需,就是查验到输入缓冲区将空,或者输出缓冲区将满。

1.2 标准流

1.2.1 操作独立性

程序运行特别是计算结束时需要显示运行结果。运行结果可以随计算的深入逐步显示,也可以等全部计算都完成之后统一显示。所以,显示结果的动作应该是独立的,不应该嵌在其他功能语句中,而是随需要而执行,故用单独的输出语句来完成输出的任务。之前的输出语句正是这样用的。

1.2.2 标准流设备

cin和cout是C++中的标准流。标准以为着其他一切流设备只要建立同样结构的流设施,则其操作就可以与此流设备相同。而标准流设备则意味着通常的流操作的制定的默认设备。标准流输入设备指的是键盘,标准流输出设备指的是控制台窗口。这就是为什么只要一进行cin的>>操作,就将会从键盘等待,一进行cout的<<操作,就将会在控制台窗口看到显示结果。

1.3. 标准设备与标准流

1.3.1 差别

标准设备是C语言对控制台开发的输入/输出设施,标准流是C++语言对控制台开发的输入/输出设施,两者虽然都实现了控制台的输入/输出,但是实现原理大相径庭。它们操作原理不同,操作也不同,一个是通过函数调用,一个是通过数据类型中的成员操作来实现输输入\输出,所以两者不能混用。

1.3.2 标准化的意义

输入/输出语句依赖于输入/输出设备。设备是多种多样的,但是所设计的输入/输出操作不论什么设备都应该一样。这就是设备的标准化的意义。一旦标准化,输入/输出操作就不会因为设备不同而不同,就比较简单了。

当在程序中指定某个设备为流设备后,只要做标准流操作就可以对该设备进行存取访问了。文件流(头文件为fstream)和子串流(头文件为stringstream)就是很特殊的两种流设备。

1.3.3 作为数据类型

标准流在C++中实现为一种数据类型。依赖于数据类型,它的操作就容易被添加而扩展,从而能方便地识别任何自定义的数据类型,接受这些类型实体的输出;依赖于数据类型,其他设备也很容易被该流类型所捆绑(继承),从而可用标准流操作访问其他设备;依赖于数据类型,通过在数据类型中定义错误处理类和一场标准,其流操作便更安全,及时遇到设备以外或者错误,可以从从容应对。这是C标准设备操作所望尘莫及的,也是用标准流操作代替标准设备操作的关键所在。

2 输入流

C++的输入流可以按存放的数据实体类型而去识别实际的数据。例如,对于下列数据:

123          5.6           2.3E-3

则流输入语句通过下列操作便能分别识别:

int a;
double b,c;
cin>>a>>b>>c;    //得到:a为123,b为5,6,c为0.0023

输入流还可以识别任何扩展的数据类型。例如,string类型是一种扩展的数据类型,它能使输入流能够识别不带空格的字串"Hello":

string s;
cin>>s;

3 输出流控制

C++的标准输出流定义了一组输出操作,"<"是其中的一种用得很频繁的操作。用"<<"可以进行格式控制,下列是一些常用的格式控制。

3.1 换行输出

换行有两种,一种是'\n'字符,另一种是对象endl。

endl的概念:

endl是end of line的意思,输出endl(即cout<<endl)表示输出换行并且刷新缓冲区。作为控制台操作,则等价于cout<<"\n"或者cout<<'\n'。

endl从输出内容上说与换行控制符相同,但是它本质上是一种依附于流的对象,功能上还有刷新缓冲区的作用。

缓冲区是一种输入/输出的内存设施,用于协调CPU与设备之间的速度落差。设备运行速度慢,CPU运行速度则要快很多,所以原始的计算机中,CPU访问设备总是要无谓的等待;现代的计算机,设备控制都配备了缓冲区机制,其CPU一看要读数据的设备之缓冲区没有数据,或者要写数据的设备之缓冲区数据已满,就立即去做别的事,等到输入设备发出数据已准备好,或者输出设备的缓冲区数据已读光(需要继续输送数据),CPU才转而去处理该设备。处理设备实际上也就是发命令读写缓冲区而已。设备运行时域缓冲区打交道,CPU运行时也与缓冲区打交道。CPU不予设备直接打交道,这使得CPU不必等待设备,设备也不会拖累CPU了。

刷新缓冲区,就是命令设备将缓冲区的数据清空(马上写到输出设备上),这在控制台窗口上并不见效,而在文件中,对于输出命令,为了处理效率,往往要等缓冲区满了才往文件介质上写数据,除非明确街道书信命令。

————————————————————————————————————————————————————————

初学编程,许多实验都是把输出送到控制台窗口上,而不是送到文件中,所以,endl与"\n"没有控制上的差别,但是因为endl要多做一些事情,会在性能上落下分。

而且"\n"与字串是同性质的,可以拼接而简化输出操作,而endl与字串彼此不相容,只能作为两个独立的数据项分送输出操作。

cout<<"Hello\n";    //等价于cout<<"Hello"<<endl;

3.2 各进制数控制

3.2.1 数制设置

用hex、oct、dec可以控制整型的各进制的输出显示。hex是hexadecimal的意思,即十六进制,oct是octonal的意思,即八进制,dec是decimal的意思,即十进制。

cout<<oct<<18<<'\n';    //输出22
cout<<hex<<255<<"\n";    //输出ff

18和255都是十进制整型字面值,用了前置的oct或者hex之后,显示的就是八进制和十六进制数了。

3.2.2 区别各进制数

八进制数看上去像十进制数,虽然在机器内部绝不会搞错,但是凭人们的肉眼容易搞错。为了区别于十进制的表示形式,可以有选择性地使用showbase格式控制。也就是在八进制数前面加0,十六进制数前面加0x。  

cout<<18<<" "<<hex<<18<<" "<<showbase<<18<<" "<<oct<<18;

可以得到:

18 12 0x12 022

同样是十六进制数12,有没有showbase则显示效果不一样。

3.2.3 十六进制大小写

十六进制格式输出时,其中由a,b,c,d,e,f这六个字母数字表示10、11、12、13、14、15,输出时有小写大写之分,可以通过uppercase控制。

cout<<hex<<255<<" "<<uppercase<<255;    //输出:ff FF

十六进制数没有对应的lowercase格式控制,但其默认十六进制的字母数字为小写输出。通过uppercase设置成大写后,可以通过nouppercase恢复到小写格式输出。

cout<<hex<<255<<" "<<nouppercase<<255;    //输出:FFff

因为当前状态已经是uppercase了,所以输出的是大写十六进制数,结果nouppercase便把状态设置恢复到小写状态。

uppercase值控制十六进制数的字母大小写,并不控制字符型字母的大小写。

char x = 'w';
cout<<x<<" "<<uppercase<<x<<"\n";    //输出:w w

3.3 小数输出

3.3.1 一般形式

cout的<<操作的默认的小数输出为一般形式的小数输出,它显示6位有效位数。例如:

double x = 32.456484;
double y = 0.0000168465168;
cout<<x<<"\n";    //输出:32.456484
cout<<y<<"\n";    //输出:1.68465168E-05

一般形式的小数输出的特点是,当浮点数的小数点偏离到无法有效地用固定小数表示的时候,输出流就会自动地用科学计数法表示,y值的输出便是如此。但不管怎么显示,小数点位数或多或少,有效位数默认的是6位。

小数点的一般输出有一个缺点,就是并不能保证小数点对齐,因为有效位有些可能在小数点前,有些在小数点后;也不能保证有效位对其,因为它不显示小数点尾部的0.例如:

double z = 32.10000000067;
cout<<z<<"\n";//输出:32.1

3.3.2 定点方式

有些小数需要在输出的时候,始终保持一定的位数,这时候就需要用fixed格式控制。例如,接着对于上述x,y,可以:

cout<<fixed<<x<<"\n";    //输出:32.454568
cout<<y<<"\n";    //输出:0.000032

fixed格式控制,只能控制现有小数的精度,对于偏离小数点比较大的有效数就不能保证精度了。另外,若没有专门设置精度,则默认的精度也为6位。y值最后只能显示0.000032便说明了这一点。

3.3.3 科学表示法

用scientific格式可以控制小数以科学表示法输出,它的表示形式是规格化的,也就是说,十进制数的小数点前有一位非0数,然后,小数点后面保留固定的精度,默认为6位。例如,上述x、y的输出改为scientific,则:

cout<<scientific<<x<<"\n";    //输出:3.241457E+01
cout<<y<<"\n";    //输出:3.241457E-05

在科学计算中,往往会涉及偏离小数点位数很远的数,比如一个宏观的天文数字或者一个微观的微尘数字。用scientific格式输出,能够充分表现浮点数的有效位,在科学计算中很有用。

取消小数格式控制的对应方式是:

cout.unsetf(ios::scientific);
cout.unsetf(ios::fixed);

它作为成员函数的操作方式,表示为独立的语句。

3.3.4 带参数的格式控制

流中控制精度也好,宽度也好,填充字符也好,都是带有参数的操作,所以需要成员函数型操作。流的成员函数声明都在头文件中iomanip中,所以需要包含,即:

#include<iomanip>

3.3.4.1 精度设置

用setprecision(n)设置值小数精度为n位,对于一般形式的小数,则为有效位数。例如:

double x = 32.414567;
double y = 0.00000032414567;
cout<<setprecision(4);    //默认为一般小数方式(有效位数为4)
cout<<x<<"\n";    //输出:32.41
cout<<y<<"\n";    //输出3.241e-07
cout<<fixed;    //定点方式(小数4位)
cout<<x<<"\n";    //输出:32.4146
cout<<y<<"\n";   //输出:0.0000
cout<<scientific;    //科学方式(小数4位)
cout<<x<<"\n";    //输出:3.2415e+01
cout<<y<<"\n";    //输出:3.2415e-07

一旦设置了有效位数4位,在后面设置固定方式小数输出时,该4位就变成了精度,同样,科学方式设置时,精度为4位不变。除非重新进行格式控制,设置精度值。

从中看出,固定方式和科学方式,都能小数对其,或者尾数对齐,而对于一般小数方式,由于用有效位数表示,无法对齐。

3.3.4.2 宽度设置

用setw(n)设置显示宽度为n个字符。设置了宽度后,下一个输出项便在该宽度中显示。如果宽度值不够显示的字符数,则宽度值无效;如果宽度值超过显示的字符数,则余下的字符用内定填充字符填充。默认的内定填充字符为空格。设置宽度的原因许多时候时为了对齐。例如:

int a = 18,b = 123, c = 1230;
cout<<setw(5)<<a<<"\n";
cout<<setw(5)<<b<<"\n";
cout<<setw(5)<<c<<"\n";
cout<<setw(3)<<c<<"\n";

得到输出结果为:

    18
   123
  1230
 1230

因为c的数值有4位,超过了宽度预置,所以宽度设置便不骑作用。setw(n)操作支队紧接着的下一项输出操作有效,之后便无效了。所以上述代码需要每次重新设置的宽度的格式控制。

3.3.4.3 填充字符设置

在一些场合需要输出中对齐或者带填充字符,便需要设置填充字符。用setfill(c)设置的默认填充字符为c。例如:

cout<<setw(6)<<setfill('$')<<27<<'n';    //输出:$$$$27

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值