C/C++程序设计
1
C++ 语言本身没有输入输出函数。 C语言中是通过 FILE描述的结构进行 I/O处理,C++的 I/O类库平行于这个 FILE结构建立一套面向对象的输入输出方式。 FILE结构的实例称为流文件,I/O类的实例称为流对象。
流对象提供两个特点:一个是数据类型安全的自动匹配,另一个是可以对集合类型数据进行输入输出重载。
C/C++程序设计
2
五、格式化的输入输出
C/C++程序设计
3
五、格式化的输入输出流对象有两种平行的方法用于格式控制:
一、是利用成员函数 ;
二、是采用操作算子 。
C/C++程序设计
4
1,操作算子 (manipulator)的概念
I/O流类库的格式化输入输出是通过成员函数和一些 I/O
操作算子 (manipulator)进行的。操作算子通常是返回确定数据类型的函数名,密切地与影响数据流的预先定义的对象相联系。这些操作算子作为特定类型的表达式,可以作为右操作数出现在 operator<<运算符重载函数中,例如,
cout<<setw(2)。通过操作算子可以改变数据的转换格式,
或者执行一个特定的动作。操作算子对格式控制的有效性一般持续到另一次新的设置。
带整型参数的操作算子需要 #include <iomanip.h>指令予以支持。
C/C++程序设计
5
2,整数转换的操作算子 hex,oct,dec
下面是进行 I/O整数转换的操作算子 (manipulator) 的名称和含义:
dec —— 以有符号整数十进制格式 (缺省模式 )解释后续域。可以进行读写操作。
hex —— 以无符号整数十六进制格式解释后续域。
可以进行读写操作。
oct —— 以无符号整数八进制格式解释后续域。
可以进行读写操作。
C/C++程序设计
6
操作算子的 dec,hex,oct 的全局函数原型分别为:
ios& dec(ios&); ios& hex(ios&); ios& oct(ios&);
相应地 cout<< dec<< hex<< oct等启动下面的成员函数:
inline ostream& ostream::operator<<
(ios& (*f)(ios& )) { (*f)(*this); return *this; }
其中 f是 ios& (*)(ios& )型的函数指针,(*f)(*this)是间接调用实参 dec,hex,oct对应的函数。
相应地 cin>>dec>> hex>> oct等启动下面的成员函数:
inline istream& istream::operator>>
(ios& (* f)(ios&)) { (*f)(*this); return *this; }
这些格式转换的作用具有持续性,如果用 hex设置 16进制数的输出到 cout。
C/C++程序设计
7
[例 ] 操作算子的 hex,oct,dec 的用法
# include<iostream.h>
signed short a=65535;
unsigned short b=-1;
void main()
{ cout<<dec<<a<<','<<dec<<(unsignedshort)a
<<‘,‘ <<hex<<a<<’,’<<oct<<a<<‘;’;
cout<<dec<<(signedshort)b<<','<<dec<<b<<',‘
<<hex<<b<<','<<oct<<b<<endl;
}
比较:
printf ("[%hd,%4hu,%4ho,%x]\n",b,b,b,b);
C/C++程序设计
8
3,自定义操作算子为方便 ostream输出操作,系统提供三个与类 ostream
相关的操作算子 endl,ends,flush。它们的名称、含义和原型 [或定义 ]如下:
endl —— 插入一个新行’ \n’。
[ ostream & endl (ostream&); ]
ends —— 插入一个结尾符’ \0’。
[ ostream & ends (ostream & outs)
{ return outs << char('\0'); } ]
flush —— 刷新流,将缓冲区的数据送到物理设备。
[ ostream & flush(ostream&); ]
C/C++程序设计
9
一个与类 istream相关的操作算子为 ws,进行 istream
输入操作。它的原型和含义如下:
istream & ws (istream & ins);
—— 忽略输入流中的空白字符。
可以定义操作算子以实现特定的格式转换,下面例题中的操作算子其函数的类型属性具有 ostream& (*)(ostream&)
的形式,以适用如下的 ostream类的运算符函数:
inline ostream & ostream::operator<<
( ostream& (* f) (ostream& ))
{ (*f)(*this); return *this; }
C/C++程序设计
10
运算符函数调用 cout<<endl启动上面这个成员函数,全局函数 endl的定义如下:
inline ostream & endl(ostream& _outs)
{ return _outs << '\n' << flush; }
C/C++程序设计
11
[例 ] ostream类操作算子的用法
# include<iostream.h>
inline ostream& cp(ostream& p) { return p<<"++++";}
inline ostream& cs(ostream& s) { return s<<"SSSS ";}
inline ostream& bell(ostream& b) { return b<<'\a'; }
inline ostream& tab(ostream& t) { return t<<'\t' ; }
void show ( ostream& (*f)(ostream& ))
{ cout<<1<<f<<2<<f<<3<<f<<bell<<" "; }
void main()
{ show(tab); show(cp); show(cs); }
输出:
1 2 3 1++++2++++3++++ 1SSSS2SSSS3SSSS
C/C++程序设计
12
4,格式化标志值在基类 ios中通过 enum引进一组称为格式化标志的立即数,供 resetiosflags,setiosflags 操作算子以及成员函数
ios::setf (long)和 ios::unsetf (long)作为入口值。这些梅举常数设置成适用于参入位的运算,位运算的结果作为标志,
控制下一个回合的格式转换。
C/C++程序设计
13
下面是关于这些梅举立即数的名称和含义说明:
ios::skipws 在输入中跳过空白
ios::left 左对齐值,用填充字符填充右边
ios::right 右对齐值,用填充字符 (缺省为空格字符 )
填充左边 (缺省对齐方式 )
ios::internal 在符号和数据之间增加填充字符
ios::dec 以十进制格式化数值 (缺省进制 )
ios::oct 以八进制格式化数值
ios::hex 以十六进制格式化数值
ios::showbase 以 C++编译器能读的格式显示数值常量
ios::showpoint 对浮点数值显示小数点和尾部的 0
C/C++程序设计
14
ios::uppercase 十六进制数显示大写字母 A到 F,对于科学格式显示大写字母 E
ios::showpos 对于正数显示正号 (+)
ios::scientific 以科学格式显示浮点数值
ios::fixed 以定点格式显示浮点数值,即显示小数点,后边的位数由精度指定。
ios::unitbuf 在每次插入之后刷新流缓冲的单元
ios::stdio 在每次插入后刷新该流的 stdout和 stderr
C/C++程序设计
15
在 ios类中定义如下 const型的公共静态成员数据:
static const long basefield;
static const long adjustfield;
static const long floatfield;
静态成员变量是约束到类的全局变量,const关键字使得相关常量具有立即数的性质。这些静态成员常量与梅举成员常数具有相同的索引形式。
C/C++程序设计
16
5,控制浮点精度操作算子 setprecision 和成员函数 ios::precision设置小数点后的精度。设置精度之后影响其后的小数点控制,除非另行设置精度。
precision存在两个版本:
[int precision(int);],[int precision() const;]。
无参的版本 precision 返回当前的精度,有参的版本设置新的精度并返回原先的值。精度用于指出输出的有效字符个数,不含小数点。
C/C++程序设计
17
[例 ] 成员函数 precision设置输出的精度
# include<iostream.h>
const double d=1.234567890123456;
void show (int n)
{ int k=cout.precision(n);
cout<<k<<","<<n<<","<<d<<"+++";
}
void main()
{ show(0); show(4); show(7); show(9);}
输出,6,0,1+++0,4,1.235+++4,7,1.234568 +++7,
9,1.23456789
C/C++程序设计
18
[例 ] 操纵算子 setprecision设置输出的精度
# include<iostream.h>
# include<iomanip.h>
const double d=1.234567890123456;
void show (int n)
{ cout<<setprecision (n)<<d<<'\t'; }
void main()
{ show(0); show(1); show(2); show(3); }
输出结果,1 1 1.2 1.23
C/C++程序设计
19
6,浮点数和科学计数法下面是这些操作算子的函数名称、入口类型和作用解释:
Resetiosflags (long f) 重新清除该流的格式标志。
Setiosflags (long f) 设置该流的格式标志。
Setprecision (int r) 设置该流的浮点显示精度。
Setfill (int c) 设置该流的填充字符。
Setw (int w) 设置该流的域宽 (仅对下一个域有效 )。
C/C++程序设计
20
与以上这些操作算子相对应的 ios类的成员函数的函数原型和含义如下:
long flags() const; 该函数返回标志值
long flags (long l); 该函数使用入口参数重新设置标志位,返回先前的标志值
long setf (long flag,long mask); 该函数用 mask设置屏蔽值,标志值由 flag中的对应位确定。
long setf (long l); 该函数设置参数指定的标志位,
返回先前的标志值。
long unsetf (long l); 该函数清除参数所指定的标志位,返回先前的标志值。
C/C++程序设计
21
[例 ] setf和 unsetf函数设置格式控制转换标志
# include<iostream.h>
const double x=1.23456789,y=1.23456789e5;
void show (int n)
{ cout<<n<<"."<<x<<'\t'<<y<<'\n'; }
void main()
{ const int floatfield=ios::scientific|ios::fixed;
cout.setf (ios::dec); show(1);
cout.setf (ios::scientific); show(2);
cout.setf (ios::scientific,floatfield); show(3);
cout.unsetf (ios::scientific); show(4);
cout.setf (ios::fixed,floatfield); show(5); }
C/C++程序设计
22
[例 ] flags成员函数设置格式转换控制标志
# include<iostream.h>
const double x=1.23456789,y=1.23456789e5;
void show (charn)
{ cout<<n<<".format:"<<x<<'\t'<<y<<'\n'; }
void main()
{ enum { floatfield=ios::scientific|ios::fixed };
show ('a');
cout.flags (ios::scientific); show ('b');
long n=cout.flags (ios::scientific&floatfield);
show ('c');
C/C++程序设计
23
cout.flags (n^ios::scientific); show ('d');
cout.flags (ios::fixed&floatfield); show ('e');
}
输出结果:
a,format:1.23457 123457
b,format:1.234568e+000 1.234568e+005
c,format:1.234568e+000 1.234568e+005
d,format:1.23457 123457
e,format:1.234568 123456.789000
C/C++程序设计
24
[例 ] 操作算子实现格式转换控制
# include<iostream.h>
# include<iomanip.h>
const double x=1.23456789,y=1.23456789e5;
void show (char n)
{ cout<<n<<".format:"<<x<<'\t'<<y<<'\n'; }
void main()
{ enum
{ floatfield=ios::scientific|ios::fixed };
show('a');
cout<<setiosflags(ios::scientific);
show('b');
C/C++程序设计
25
cout<<setiosflags (ios::scientific&floatfield);
how ('c');
cout<<resetiosflags (ios::scientific);
show('d');
cout<<setiosflags (ios::fixed&floatfield);
show('e');
} //输出结果同上例说明:
操作算子 resetiosflags是 setf(long =0,long l)成员函数的内联映射。
setiosflags是 setf (long)成员函数的内联映射。
C/C++程序设计
26
7,字符填充和宽度、对齐控制
ios类中提供了字符填充和宽度控制成员函数,其函数原型和相应的含义说明如下:
int width() const; 返回当前的宽度值。
int width (int nw); 用入口值设置格式控制的宽度,
返回先前的值。
char fill() const; 返回当前所采用的填充字符。缺省的填充字符为空格。
char fill (char c); 用入口值设置新的填充字符,返回先前的填充字符。
C/C++程序设计
27
操作算子 setw (int) 和 setfill (int c)分别是 width (int)和
fill (char c)成员函数的内联映射。
因此与相关函数存在同样的作用。宽度控制成员函数仅对下一个数据的控制有效。
整型数的输出转换无宽度控制时,多个数据首尾相连地输出。
例如:
cout<<12<<','<<123456789; //输出 12,123456789
C/C++程序设计
28
[例 ] 字符填充和宽度、对齐控制
# include<iostream.h>
# include<iomanip.h>
void main() //下面用?醒目地表示空格。
{ cout.setf (ios::right);cout.width(5);
cout<<12<<','<<123456; //输出,12,123456
cout.width(5);cout.fill('0');
cout<<12<<','<<123456; //输出,00012,123456
cout.setf (ios::left);cout<<setw(5)<<12<<','<<123456;
//输出,12,123456
cout<<setw(5)<<setfill('+')<<12<<','<<123456;
//输出,12+++,123456
}
C/C++程序设计
29
cout.setf(ios::right)为右对齐方式,cout.setf(ios::left)
为左对齐方式。
cout.width(w)中的宽度 w为指定的输出字符个数,如果数据的字符个数小于 w,左段补充空格。 如果数据的字符个数大于 w,输出实际数据的长度。
默认的填充字符为空格。右对齐方式左补空格,左对齐方式右补空格。
可用 cout.fill (c)或 cout << setfill (c)设置填充字符,更改默认的方式。
C/C++程序设计
30