您的位置:首页 > 编程语言 > C语言/C++

C++流格式控制(2006-9-25 15:25:00…

2015-10-08 00:21 288 查看

C++流格式控制(2006-9-25
15:25:00)

【收藏】 【评论】 【打印】 【关闭】

格式 控制
   当输入/输出的数据没有指定格式,它们都按缺省的格式输入/输出。然而,有时需
要对数据格式进行控制。这时需利用ios类中定义的
格式控制成员函数,通过调用它们来完成格式的设置。ios类的格式控制函数如下所示:

long
flags( ) const
返回当前的格式标志。
long
flays(long newflag)
设置格式标志为newflag,返回旧的格式标志。
long
setf(long bits)  
设置指定的格式标志位,返回旧的格式标志。
long
setf(long bits,long field)
将field指定的格式标志位置为bits,返回旧的格式标志。
 long unsetf(long bits)清除bits指定的格式标志位,返回旧的格式标志。
long
fill(char c) 
设置填充字符,缺省条件下是空格。
  char fill( )  返回当前填充字符。
int
precision(int val) 
设置精确度为val,控制输出浮点数的有效位,返回旧值。
int
precision( )
返回旧的精确度值。
int
width(int val)
    
设置显示数据的宽度(域宽),返回旧的域宽。
int width(
只返回当前域宽,缺省宽度为0。这时插入操作能按表示数据的最小宽度显示数据。 
预定义的操纵算子
   
使用成员函数控制格式化输入输出时,每个函数调用需要写一条语句,尤其是它不能用在插入或提取运算符的表达式中,而使用操纵算子,则可以在插入和提取运算
符的表达式中控制格式化输入和输出。在程序中使用操纵算字 必须嵌入头文件iomanip.h

dec十进制的输入输出
 hex十六进 制的输入输出
 oct  八进制的输入输出
ws  提取空白字符
 ends  输出一个nul字符
endl 输出一个换行字符,同时刷新流
flush刷新流
resetiosflags(long)请除特定的格式标志位
setiosflags(long)设置特定的格式标志位
setfill(char)设置填充字符
setprecision(int)设置输出浮点数的精确度
 setw(int)设置域宽格式变量
其它 流函数
错误处理
   在对一个流对象进行I/O操作时,可能会产
生错误。当错误发生时,错误的性质被记录在ios类的一个数据成员中。
ios类中定义的描述错误状态的常量:

 

goodbit 没有错误,正常状态  eofbit 到达流的结尾
  
failbitI/O 操作失败,清除状态字后,可以对流继续进行操作。
badbit试图进 行非法操作,清除状态字后,流可能还可以使用。
hardfail致命错 误,不可恢复的错误。
ostream类 的成员函数
流的其它成员函数可以从流中读取字符或字符串,对流进行无格式化的输入
输出操作,以及直接控制对流的I/O操作。
 

返 回类型ios 类的成员描       述
ostream*tie(ostream*)   将当前流与指定的输出流连接起来。每当需要
读取当前流时,连接的流会自动刷新。C++流库已用cin.tie(cout)将输入流与输出流连接起来。要取消与输出流的连接可采用is.tie(0)
ostream*tie( )返回指向连接流的指针
 

返回类型ostream 类的成员描       述
ostream&put(char ch)向流中输出一个字符ch,不进行 任何转换
ostream&write(char*,int)向流中输出指定长度的字符串,不 进行转换
ostream& flush( )刷新流,输出所有缓冲的但还未输 出的数据
ostream&seekp(streampos)移动流的当前指针到给定的绝对位 置
ostream&seekp(sereamoff,seek_dir)流的当前指针类似与文件的当前指 针
streamposteelp( )返回流的当前指针的绝对位置
istream类的成员函 数
 

返 回类型istream 类的成员描         述
intget( )读取并返回一个字符
istream&get(char&c)读取字符并存入c中
istream&get(char*ptr,int len,char delim='')读取指定的字符到缓冲区中,直到 遇到指定的分界符为止,分界符不填入缓冲区。
istream&getline(char*ptr,int len,char delim='')与get(char*ptr,int len,chardelim ='')
类似,但将分界符填入缓冲区。
istream& putback( )将最近读取的字符放回流中
istream&read(char*,int)读取规定长度的字符串到缓冲区中
intpeek( ) 返回流 中下一个字符,但不移动文件指针
istream&seekg(streampos)移动当前指针到一绝对地址
istream& seekg(streampos,seek_dir)移动当前指针到一相对地址
streampostellg( )返回当前指针
istream&ignore(int n=1,delim=EOF)跳过流中几个字符,或直到遇到指 定的分界符为止
附:以16进制形式打印内存数据:

#include <iostream>

#include <iomanip>

using namespace std;

void foo( const void* buf, size_t len )

{

    const
unsigned char* p = (const unsigned char*)buf;

    for( size_t
i=0; i<len; ++i )

    {

       
cout << setfill('0')
<< setw(2)
<< uppercase
<< hex
<< (unsigned)p[i]
<< ' ';

    }

    cout
<< endl;

}

int main( void )

{

    char *test1
= "\x00\x01\x10\xFF";

    foo( test1,
4 );

   
double  test2 = 123.456;

    foo(
&test2, 8 );

   return 0 ;

};

输出:

00 01 10 FF

77 BE 9F 1A 2F DD 5E 40

 

补充(2008-11-06):

每一个iostream库对象都维护了一个格式状态(format
state),它控制格式化操作的细节,比如整型值的进制基数或浮点数值的精度。C++为程序员提供了一组预定义的操纵符,可用来修改一个对象的格式状
态。

操纵符被应用在流对象上的方式,就好像它们是数据一样。但是,操纵符不导致读写数据,而是修改流对象的内部状态。例如,缺省情况下,true值的
bool对象被写成整数值1:

#include <iostream>

int main()

{

  bool illustrate = true;;

  cout << "bool
object illustrate set to true: "

   
<< illustrate
<< '\n';

}

为了修改cout,使它能够把illustrate显示为true,我们应用boolalpha操纵符:

#include <iostream>

int main()

{

  bool illustrate = true;;

  cout << "bool
object illustrate set to true: ";

  // 改变cout的状态

  // 用字符串true和false输出bool值

  cout <<
boolalpha;

  cout << illustrate
<< '\n';

}

因为操纵符被应用之后,仍然返回原来被应用的流对象,所以我们可以把它的应用与数据的应用连接起来(或者与其他操纵
符的应用连接起来)。下面是重写之后的小程序,它混合了数据和操纵符:

#include <iostream>

int main()

{

  bool illustrate = true;

  cout << "bool
object illustrate: "

     
<< illustrate

     
<< "\nwith boolalpha applied: "

     
<< boolalpha
<< illustrate
<< '\n';

  // ...

}

像这样,把操纵符和数据混合起来容易产生误导作用。应用操纵符之后,不只改变了后面输出值的表示形式,而且修改了
ostream的内部格式状态。在我们的例子中,整个程序的余下部分都将把bool值显示为true或false。

为了消除对cout的修改,我 们必须应用noboolalpha操纵符:

cout << boolalpha  
// 设置cout的内部状态

  <<
illustrate

  << noboolalpha //
解除cout内部状态

我们将会看到,许多操纵符都有类似的“设置/消除(set/unset)”对 。

缺省情况下,算术值以十进制形式被读写。程序员可以通过使用hex、oct和dec操纵符,把整数值的进制基数改为八进制或十六进制,或改回十
进制(浮点值的表示不受影响)。例如:

#include <iostream>

int main()

{

int ival = 16;

double dval = 16.0;

cout << "ival: "
<< ival

  << " oct set: "
<< oct
<< ival
<< "\n";

cout << "dval: "
<< dval

  << " hex set: "
<< hex
<< dval
<< "\n";

cout << "ival: "
<< ival

  << " dec set: "
<< dec
<< ival
<< "\n";

}

编译并执行程序,产生下列输出:

ival: 16 oct set: 20

dval: 16 hex set: 16

ival: 10 dec set: 16

我们这个程序的一个问题是,我们在看到一个值的时候无法知道它的进制基数。例如,20是真正的20,还是16的八进制表示?操纵符
showbase可以让一个整数值在输出时指明它的基数,形式如下:

1.0x开头表明是十六进制数(如果希望显示为大写字母,则可以应用
uppercase操纵符;为了转回小写的x,我们可以应用nouppercase操纵符)。

2.以0开头表示八进制数。

3.没有任何前 导字符,表示十进制数。

下面是用showbase改写过的程序:

#include <iostream>

int main()

{

  int ival = 16;

  double dval = 16.0;

  cout <<
showbase;

  cout << "ival: "
<< ival

     
<< " oct set: "
<< oct
<< ival
<< "\n";

  cout << "dval: "
<< dval

     
<< " hex set: "
<< hex
<< dval
<< "\n";

  cout << "ival: "
<< ival
<< " dec set: "

     
<< dec
<< ival
<< "\n";

  cout <<
noshowbase;

}

下面是修改后的输出:

ival: 16 oct set: 020

dval: 16 hex set: 16

ival: 0x10 dec set: 16

noshowcase操纵符重新设置cout,使它不再显示整数值的进制基数。

缺省情况下,浮点值有6位的精度。这个值可以
用成员函数precision(int)或流操纵符setprecision()来修改(若使用后者,则必须包含iomanip头文件)。
precision()返回当前的精度值。例如:

#include <iostream>

#include <iomanip>

#include <math.h>

int main()

{

  cout <<
"Precision: "

     
<< cout.precision()
<< endl

     
<< sqrt(2.0)
<< endl;

  cout.precision(12);

  cout <<
"\nPrecision: "

  <<
cout.precision() << endl

  << sqrt(2.0)
<< endl;

  cout <<
"\nPrecision: " <<
setprecision(3)

  <<
cout.precision() << endl

  << sqrt(2.0)
<< endl;

  return 0;

}

编译并执行程序,产生以下输出:

Precision: 6

1.41421

Precision: 12

1.41421356237

Precision: 3

1.41

带有一个实参的操纵符,比如前面见到的setprecision()和setw(),要求包含iomanip头文件:

#include <iomanip>

我们的例子没有说明setprecision()的两个更深入的方面:1)整数值不受影响,2)浮点值被四舍五入
而不是被截取。因此当精度为4时,3.14159变成3.142,精度为3时变成3.14。

缺省情况下,当小数部分为0时,不显示小数点。例如:

cout << 10.00

输出为

10

为了强制显示小数点,我们使用showpoint操纵符:

cout << showpoint

  << 10.0

  << noshowpoint
<< '\n';

noshowpoint操纵符重新设置缺省行为。

缺省情况下,浮点值以定点小数法显示。为了改变为科学计数法,我们使
用scientific操纵符。为了改回到定点小数法,我们使用fixed操纵符:

cout << "scientific: "
<< scientific

  << 10.0

  << "fixed decimal:
" << fixed

  << 10.0
<< '\n';

这产生

scientific: 1.0e+01

fixed decimal: 10

如果希望把‘e’输出为‘E’,我们可以使用uppercase操纵符。要转回小写字母,我们使用nouppercase操纵
符。(uppercase操纵符不会使所有字母字符都显示为大写!)。

缺省情况下,重载的输入操作符跳过空白字符(空格、制表符、换行符、走纸、 回车)。已知序列

a b c

d

循环

char ch;

while ( cin >> ch )

    // ...

执行四次,以读入从a到d的四个字符,跳过中间的空格、可能的制表符和换行符。操纵符noskipws使输入操作符不跳过空白字
符:

char ch;

cin >> noskipws;

while ( cin >> ch )

    // ...

cin >> skipws;

现在while循环需要迭代七次,才能读入字符a到d。为了转回到缺省行为,我们在cin上应用操纵符skipws。

当 我们写

cout << "please enter a value:
";

文字字符串被存储在与cout相关联的缓冲区中。有许多种情况可以引起缓冲区被刷新——即,清空——在我们的例子中,也就是将缓冲区写到标准
输出上:

1.缓冲区可能会满,在这种情况下,它必须被刷新,以便读取后面的值。

2.我们可通过显式地使用flush、ends或endl 操纵符来刷新缓冲区。

// 清空缓冲区

cout << "hi!"
<< flush;

// 插入一个空字符然后刷新缓冲区

char ch[2]; ch[0] = 'a'; ch[1] = 'b';

cout << ch
<< ends;

// 插入一个换行符然后刷新缓冲区

cout << "hi!"
<< endl;

3.unitbuf,一个内部的流状态变量,若它被设置,则每次输出操作后都会清空缓冲区。

4.一个ostream对
象可以被捆绑到一个istream上,在这种情况下,当istream从输入流读取数据时,ostream的缓冲区就会被刷新。cout被预定义为“捆
绑”在cin上:

cin.tie( &cout );

语句

cin >> ival;

使得与cout相关联的缓冲区被刷新。

一个ostream对象一次只能被捆绑到一个istream对象上,为了打破现有的捆 绑,我们可以传递一个实参0。例如:

istream is;

ostream new_os;

// ...

// tie() 返回现有的捆绑

ostream *old_tie = is.tie();

is.tie( 0 ); // 打破现有的捆绑

is.tie( &new_os ); // 设置新的捆绑

// ...

is.tie( 0 ); // 打破现有的捆绑

is.tie( old_tie ); // 重新建立原来的捆绑

我们可以用setw()操纵符来控制数字或字符串值的宽度。例如程序

#include <iostream>

#include <iomanip>

int main()

{

  int ival = 16;

double dval = 3.14159;

cout << "ival: "
<< setw(12)
<< ival
<< '\n'

   
<< "dval: "
<< setw(12)
<< dval
<< '\n';

}

产生以下输出:

ival:      
16

dval:     3.14159

第二个setw()是必需的,因为不像其他操纵符,setw()不修改ostream对象的格式状态。

要想使输出 的值左对齐,我们可以应用left操纵符(通过right操纵符可以重新设回到缺省状态)。如果我们希望产生

  16

-   3

我们可以应用internal操纵符,它使得正负符号左对齐,而值右对齐,中间添加空格。如果希望用其他字符填充中间的空白,则可以应
用setfill()操纵符。

cout << setw(6)
<< setfill('%')
<< 100
<< endl;

产生

%%%100

预定义的所有操纵符都被列在表20.1中。

操 纵 符 含     义

boolalpha 把true 和 false 表示为字符串

*noboolalpha 把true 和 false 表示为0、1

showbase 产生前缀,指示数值的进制基数

*noshowbase 不产生进制基数前缀

showpoint 总是显示小数点

*noshowpoint 只有当小数部分存在时才显示小数点

Showpos 在非负数值中显示 +

*noshowpos 在非负数值中不显示 +

*skipws 输入操作符跳过空白字符

noskipws 输入操作符不跳过空白字符

uppercase 在十六进制下显示 0X , 科学计数法中显示E

*nouppercase 在十六进制下显示 0x, 科学计数法中显示e

*dec 以十进制显示

hex 以十六进制显示

oct 以八进制显示

left 将填充字符加到数值的右边

right 将填充字符加到数值的左边

续表

操 纵 符 含     义

Internal 将填充字符加到符号和数值的中间

*fixed 以小数形式显示浮点数

scientific 以科学计数法形式显示浮点数

flush 刷新ostream缓冲区

ends 插入空字符,然后刷新ostream缓冲区

endl 插入换行符,然后刷新ostream缓冲区

ws “吃掉” 空白字符

// 以下这些要求 #include <iomanip>

setfill( ch ) 用ch填充空白字符

setprecision( n ) 将浮点精度设置为 n

setw( w ) 按照w个字符来读或者写数值

setbase( b ) 以进制基数 b 输出整数值

* 表示缺省的流状态

iostream库是强类型的。例如,试图从一个ostream读数据,或者写数据到一个istream,都会在编译时
刻被捕获到,并标记为类型违例。例如,已知下列声明

#include <iostream>

#include <fstream>

class Screen;

extern istream&
operator>>( istream&,
const Screen& );

extern void print( ostream& );

ifstream inFile;

下面的两条语句都将导致编译时刻类型违例:

int main()

{

  Screen myScreen;

  // 错误:期望一个 ostream&

  print( cin >>
myScreen );

  // 错误:期望 >>
operator

  inFile << "error:
output operator";

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: