加载中…
个人资料
himdd
himdd
  • 博客等级:
  • 博客积分:0
  • 博客访问:2,128
  • 关注人气:0
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
相关博文
推荐博文
谁看过这篇博文
加载中…
正文 字体大小:

C++大学教程(第11章 C++输入/输出流-01)

(2010-09-15 09:37:19)
标签:

杂谈

分类: Cpp
教学目标
    ●了解怎样使用C 面向对象的输入/输出流
    ●能够格式化输入和输出
    ●了解I/O流类的层次结构
    ●了解怎样输入/输出用户自定义类型的对象
    ●能够建立用户自定义的流操纵算子
    ●能够确定/输出操作的成功与失败
    ●能够把输入输出流连到输人流上

11.1  简介
    C 标准库提供了—组扩展的输入/输出(I/O)功能。本章将详细介绍C 中最常用的一些I/O 操作,并对其余的输入/输出功能做一简要的概述。本章的有些内容已经在前面提到,这里对输入/输出功能做一个更全面的介绍。
    本章讨论的许多输入/输出功能都是面向对象的,读者会发现C 的I/O操作能够实现许多功能。C 式的I/O中还大量利用了C 的其他许多特点,如引用、函数重载和运算符重载等等。
    C 使用的是类型安全(typesafe)的I/O操作,各种I/O操作都是以对数据类型敏感的方式来执行的。假定某个函数被专门定义好用来处理某一特定的数据类型,那么当需要的时候,该函数会被自动调用以处理所对应的数据类型。如果实际的数据类型和函数之间不匹配,就会产生编译错误。
  因此,错误数据是不可能通过系统检测的(C语言则不然。这是C语言的漏洞,会导致某些相当微妙而又奇怪的错误)。
    用户既可以指定自定义类型的I/O,也可以指定标准类型的I/O。这种可扩展性是C 最有价值的特点之一。

    编程技巧11.1
    尽管C语言式的I/O在C 中是可以使用的,但还是应该尽量使用C 特有的I/O格式。

    软件工程视点11.1
    C 式的I/O是类型安全的。

    软件工程视点11. 2
    C 允许对预定义类型和自定义类型的I/O用同样的方法处理.从而可加快软件的开发过程,特别是能够提高软件的复用性。

11.2 
    C 的I/O是以字节流的形式实现的,流实际上就是一个字节序列。在输入操作中,字节从输入设备(如键盘、磁盘、网络连接等)流向内存;在输出操作中,字节从内存流向输出设备(如显示器、打印机、磁盘、网络连接等)。
    应用程序把字节的含义与字节关联起来。字节可以是ASCII字符、内部格式的原始数据、图形图像、数字音频、数字视频或其他任何应用程序所需要的信息。
    输人/输出系统的任务实际上就是以一种稳定、可靠的方式在设备与内存之间传输数据。传输过程中通常包括一些机械运动,如磁盘和磁带的旋转、在键盘上击键等等,这个过程所花费的时间要比处理器处理数据的时间长得多,因此要使性能发挥到最大程度就需要周密地安排I/O操作。一些介绍操作系统的书籍(见参考文献Dc9O)深入地讨论了这类问题。
    C 提供了低级和高级I/O功能。低级I/O功能(即无格式I/O)通常只在设备和内存之间传输一些字节。这种传输过程以单个字节为单位.它确实能够提供高速度并且可以大容量的传输,但是使用起来不太方便。
    人们通常更愿意使用高级I/O功能(即格式化I/O)。高级I/O把若干个字节组合成有意义的单位,如整数、浮点数、字符、字符串以及用户自定义类型的数据。这种面向类型的I/O功能适合于大多数情况下的输入输出,但在处理大容量的I/O时不是很好。

    性能提示11.1
    处理大容量文件最好使用无格式I/O。

11.2.1  iostream类库的头文件
    C 的iostream类库提供了数百种I/O功能,iostream类库的接口部分包含在几个头文件中。
    头文件iostream.h包含了操作所有输入/输出流所需的基本信息,因此大多数C 程序都应该包含这个头文件。头文件iostream.h中含有cin、cout、cerr、clog 4个对象,对应于标准输入流、标准输出流、非缓冲和经缓冲的标准错误流。该头文件提供了无格式I/O功能和格式化I/O功能。
    在执行格式化I/O时,如果流中带有含参数的流操纵算子,头文件iomanip.h所包含的信息是有用的。
    头文件fstream.h所包含的信息对由用户控制的文件处理操作比较重要。第13章将在文件处理程序中使用这个头文件。
    每一种C 版本通常还包括其他一些与I/O相关的库,这些库提供了特定系统的某些功能,如控制专门用途的音频和视频设备。

11.2.2  输入/输出流类和对象
    iostream类库包含了许多用于处理大量I/O操作的类。其中,类istream支持流输入操作.类ostream支持流输出操作,类iostream同时支持流输入和输出操作。
    类istream和类ostream是通过单一继承从基类ios派生而来的。类iostream是通过多重继承从类istream和ostream派生而来的。继承的层次结构见图11.1。
    运算符重载为完成输入/输出提供了一种方便的途径。重载的左移位运算符(<<)表示流的输出,称为流插入运算符;重载的右移位运算符(>>)表示流的输入,称为流读取运算符。这两个运算符可以和标准流对象cin、cout、cerr、clog以及用户自定义的流对象—起使用。

C++大学教程(第11章 <wbr>C++输入/输出流-01)

    cin是类istream的对象,它与标准输入设备(通常指键盘)连在一起。下面的语句用流读取运算符把整数变量grade(假设grade为int类型)的值从cin输入到内存中。
    cin >> grade;
  注意,流读取运算符完全能够识别所处理数据的类型。假设已经正确地声明了grade的类型,那么没有必要为指明数据类型而给流读取运算符添加类型信息。
    cout是类ostream的对象,它与标准输出设备(通常指显示设备)连在一起。下面的语句用流插入运算符cout把整型变量grade的值从内存输出到标准输出设备上。
    cout << grade;
  注意,流插入运算符完全能够识别变量grade的数据类型,假定已经正确地声明了该变量,那么没有必要再为指明数据类型而给流插入运算符添加类型信息。
    cerr是类osteam的对象,它与标准错误输出设备连在一起。到对象cerr的输出是非缓冲输出,也就是说插入到cerr中的输出会被立即显示出来,非缓冲输出可迅速把出错信息告诉用户。
    clog是类ostream的对象,它与标准错误输出设备连在一起。到对象clog的输出是缓冲翰出。即每次插入clog可能使其输出保持在缓冲区,要等缓冲区刷新时才输出。
    C 中的文件处理用类ifstream执行文件的输入操作,用类ofstream执行文件的输出操作,用类fstream执行文件的输入/输出操作。类ifstream继承了类istream,类ofstream继承了类ostream,类fstream继承了类iostream。与I/O相关的类的继承关系见图11.2。虽然多数系统所支持的完整的输入/输出流类层次结构中还有很多类,但这里列出的类能够实现多数程序员所需要的绝大部分功能。如果想更多地了解有关文件处理的内容,可参看C 系统中的类库指南。


 

C++大学教程(第11章 <wbr>C++输入/输出流-01)


11.3  输出流
    C 的类ostream提供了格式化输出和无格式输出的功能。输出功能包括:用流插入运算符输出标准类型的数据;用成员函数put输出字符;成员函数write的无格式化输出(11.5节);输出十
进制、八进制、十六进制格式的整数(11.6.1节);输出各种精度的浮点数(11.6.2节)、输出强制带有小数点的浮点数(11.7.2节)以及用科学计数法和定点计数法表示的浮点数(11.7.6节);输出在指定域宽内对齐的数据(11.7.3节);输出在域宽内用指定字符填充空位的数据(11.7.4节);输出科学计数法和十六进制计数法中的大写字母(11.7.7节)。

11.3.1  流插入运算符
    流插入运算符(即重载的运算符<<)可实现流的输出。重载运算符<<是为了输出内部类型的数据项、字符中和指针值。11.9节要详细介绍如何用重载运算符<<输出用户自定义类型的数据项。
图11.3中的范例程序用一条流插入语句显示了输出的字符串。图11.4中的范例程序用多条流插入语句显示输出的字符串,该程序的运行结果与图11.3中程序的运行结果相同。

1 // Fig. 11.3: figll 03.cpp
2 // Outputting a string using stream insertion.
3 #include <iostream.h>
4
56 int main()
  cout << "Welcome to C !\n";
8
  return O;
10 }

输出结果:
Welcome to C !

                                图 11.3 用一条流插入语句输出字符串

1 // Fig. 11.4: figllO4.cpp
2 // Outputting a string using two stream insertions.
3 #include <iostream.h>
4
5 int main()
6{
  cout << "Welcome to ";
  cout << "C !\n";
9
10   return 0;
11 }

输出结果:
Welcome to C !

                                   图 11.4 用两条流插入语句输出字符串

    也可以用流操纵算子endl(行结束)实现转义序列\n(换行符)的功能(见图11.5)。流操纵算子endl发送一个换行符并刷新输出缓冲区(不管输出缓冲区是否已满都把输出缓冲区中的内容立即输出)。也可以用下面的语句刷新输出缓冲区:
    cout << flush;
11.6节要详细讨论流操纵算子。

1 // Fig. 11.5: fig11_05.cpp
2 // Using the endl stream manipulator.
3 #include <iostream.h>
4
5 int main{)
6 {
  cout << "Welcome to ";
  cout << "c !';
  cout << endl;  // end line stream manipulator
10
11   return 0;
12 }

输出结果:
Welcome to C !

                                         图 11.5 使用流操纵算子endl

流插入运算符还可以输出表达式的值(见图11.6)

1 // Fig. 11.6: fig11_O6.cpp
2 // Outputting expression values.
3 #include <iostream.h>
4
5 int main()
6 {
  cout << "47 plus 53 is ";
8
  // parentheses not needed; used for clarity
10   cout << ( 47 53 );     // expression
11   cout << endt;
12
13   return O;
14 }

输出结果:
47 plus 53 is 100
  
                            图 11.6 输出一个表达式的值

    编程技巧11.2
    当输出表达式时,为防止表达式中的运算符与运算符<<之间存在运算符化先级问题,用括号将表达式括起来。

11.3.2  连续使用流插入/流读取运算符
   
重载的运算符<<和>>都可以在一条浯句中连续使用(见图11.7)。
  file://  Fig.11.7: fig11_07.cpp
  file://  Cascadlng the overlOadGd << OPeratOr.
  #includc<iostream.h>
  4
  int  main()
  {
    cout << "47 plus 53 is " << ( 47 53 ) << endl;
  8
    return  O;
 10  }

输出结果:
47 plus 53 is 100

                        图 11.7 连续使用重载运算符<<

    图中多次使用流插入运算符的语句等同于下面的语句:
    ((( cout << " 47 plus 53 is " ) << 47 53 ) << endl);
之所以可以使用这种写法,是因为重载的运算符<<返回了对其左操作数对象(即cout)的引用,因此最左边括号内的表达式:
    ( cout << " 47 plus 53 is " )
它输出一个指定的字符串,并返回对cout的引用,因而使中间括号内的表达式解释为:
    ( cout << ( 47 53 ) )
它输出整数值100,并返回对cout的引用。于是最右边括号内的表达式解释为:
    cout << endl;
它输出一个换行符,刷新cout并返回对cout的引用。最后的返回结果未被使用。

11.3.3 输出char*类型的变量
    C语言式的I/O必须要提供数据类型信息。C 对此作了改进,能够自动判别数据类型。但是,C 中有时还得使用类型信息。例如,我们知道字符串是char*类型,假定需要输出其指针的值,即字符串中第一个字符的地址,但是重载运算符<<输出的只是以空(null)字符结尾的char*类型的字符串,因此使用void*类型来完成上述需求(需要输出指针变量的地址时都可以使用void*类型)。图11.8中的程序演示了如何输出char*类型的字符串及其地址,辅出的地址是用十六进制格式表示。在C 中,十六进制数以0x或0X打头,11.6.1节、11.7.4节、11.7.5节和11.7.7节要详细介绍控制数值基数的方法。
1 // Fig. 11.8: fig11_08.cpp
2 // Printing the address stored in a char* variable
3 #include <iostream.h>
4
5 int main()
6{
  char *string = "test";
8
  cout << "Value of string is: "<< string
10       << "\nValue of static cast< void *>( string ) is:"
11       << static_cast< void*>( string )<<endl;
12  return 0;
13}
输出结果:
Value of string is:test
Value of staticcast <void*>( string )is:Ox00416D50

                             图 11.8 输出char*类型变量的地址

11.3.4  用成员函数put输出字符和put函数的连续调
    用put成员函数用于输出一个字符,例如语句:
    cout.put('A');
  将字符A显示在屏幕上。
    也可以像下面那样在一条语句中连续调用put函数:
    cout.put('A').put('\n');
  该语句在输出字符A后输出一个换行符。和<<一样,上述语句中圆点运算符(.)从左向右结合,put
  成员函数返回调用put的对象的引用。还可以用ASCII码值表达式调用put函数,语句cout.put(65)也
  输出字符A。

11. 4  输入流
    下面我们要讨论流的输入,这是用流读取运算符(即重载的运算符>>)实现的。流读取运算符通常会跳过输人流中的空格、tab键、换行符等等的空白字符,稍后将介绍如何改变这种行为。当遇到输入流中的文件结束符时,流读取运算符返回0(false);否则,流读取运算符返回对调用该运算符的对象的引用。每个输入流都包含一组用于控制流状态(即格式化、出错状态设置等)的状态位。当输入类型有错时,流读取运算符就会设置输人流的failbit状态位;如果操作失败则设置badbit状态位,后面会介绍如何在I/O操作后测试这些状态位。11.7节和11.8节详细讨论了流的状态位。

11.4.1  流读取运算符
    图11.9中的范例程序用cin对象和重载的流读取运算符>>读取了两个整数。注意流读运算符可以连续使用。
1 // Fig. 11.9: figll_09.cpp
2 // Calculating the sum of two integers input from the keyboard
3 // with the cin oct and the stream-extraction operator.
4 #include <iostream.h>
5
6 int main()
7{
  int x, y;
9
10  cout << "Enter two integers: ";
11  cin >> x >> y;
12  cout << "Sum of" << x << "and "<< y << "is:"
13       << ( x y ) << endl;
14
15  return 0;
16 }

输出结果:
Enter two integers: 30 92
Sum of 30 and 92 is: 122

                       图 11.9 计算用cin和流读取运算符从键盘输入的两个整数值的和

    如果运算符>>和<<的优先级相对较高就会出现问题。例如,在图11.10的程序中,如果条件表达式没有用括号括起来,程序就得不到正确的编译(读者可以试一下)。
1 // Fig. 11.10: figlll0.cpp
2 // Avoiding a precedence problem between the stream-insertion
3 // operator and the conditional operator.
4 // Need parentheses around the conditional expression.
5 #include <iostream.h>
6
7 int main()
8
  int x, y;
10
11  cout << "Enter two integers: ";
12  cin >> x >> y;
13  cout << x << ( x == y ? "is" : "is not" )
14      << "equal to "<< y << endl;
15
16  return 0;
17 }

输出结果:
Enter two integers: 7  5
7 is not equal to 5

Enter two integers: 8 8
8 is equal to 8

                       图 11.10 避免在流插入运算符和条件运算符之间出现优先级错误

        常见编程错误 11.1
        试图从类ostream的对象(或其它只有输出功能的流)中读取数据

        常见编程错误 11.2
        试图把数据写入类istream的对象(或其它只有输入功能的流)

        常见编程错误 11.3
        在流插入运算符<<或流读取运算符>>的优先级相对较高时没有用圆括号强制实现正确的计算顺序

    我们通常在while循环结构的首部用流读取运算符输入一系列值。当遇到文件结束符时,读取运算符返回0false)。图11.11中的程序用于查找某次考试的最高成绩。假定事先不知道有多少个考试成绩,并且用户会输入表示成绩输入完毕的文件结束符。当用户输入文件结束符时,while循环结构中的条件(cin>>grade)将变为0(即false)。

    可移植性提示11.1
    提示用户如何从键盘结束输入时,让用户输入文件结束符结束输入,而不是提示输入<ctrl>-d(UNIX与Macintosh所使用的)或<ctrl-z(PC与VAX所使用的)。

    在图11. 11中,cin>>grade可以作为条件,因为基类ios(继承istream的类)提供一个重载的强制类型转换运算符,将流变成void*类型的指针。如果读取数值时发生错误或遇到文件结束符,则指针值为0。编译器能够隐式使用void*类型的强制转换运算符。

1 // Fig. 11.11: figll_ll.cpp
2 // Stream-extraction operator returning false on end-of-file.
3 #include <iostream.h>
4
5 int main()
6 {
  int grade, highestGrade = -1;
8
    cout << "Enter grade (enter end-of-file to end): ";
10  while ( cin >> grade){
11     if ( grade > highestGrade )
12        highestGrade = grade;
13
14     cout << "Enter grade (enter end-of-file to end): ";
15   }
16
17   cout << "\n\nHighest grade is: "<< highestGrade << endl;
18   return 0;
19 }

输出结果:
Enter grade (enter end-of-file to end): 67
Enter grade (enter end-of-file to end): 87
Enter grade (enter end of file to end): 73
Enter grade (enter end-of-file to end): 95
Enter grade (enter end-of-file to end): 34
Enter grade (enter end-of-file to end): 99
Entergrade (enter end-of-file to end): ^ z
Heighest grade is: 99
                           
                         图 11.11 流读取运算符在遇到文件结束符时返回false

11.4.2  成员函数get和getline
    不带参数的get函数从指定的输入流中读取(输入)一个字符(包括空白字符),并返回该字符作为函数调用的值;当遇到输入流中的文件结束符时,该版本的get函数返回EOF。
    图11.12中的程序把成员函数eof和get用于输入流cin,把成员函数put用于输出漉cout。程序首先输出了cin.eof()的值,输出值为0(false)表明没有在cin中遇到文件结束符。然后,程序让用户键入以文件结束符结尾的一行文本(在IBMPC兼容系统中,文件结束符用<ctrl>-z表示;在UNIX和Macintosh系统中,文件结束符用<ctrl>-d表示)。程序逐个读取所输入的每个字符,井调用成员函数put将所读取的内容送往输出流cout。当遇到文件结束符时,while循环终止,输出cin.eof()的值,输出值为1(true)表示已接收到了cin中的文件结束符。注意,程序中使用了类istream中不带参数
的get成员函数,其返回值是所输入的字符。
1 // Fig. 11.12: figll_12.cpp
2 // Using member functions get, put and eof.
3 #include <iostream.h>
4
5 int main()
6 {
  char c;
8
  cout << "Before input, cin.eof() is "<< cin.eof()
10       << "\nEnter a sentence followed by end-of-file:\n";
11
12   while ( ( c = cin.get() ) != EOF )
13     cout.put( c );
14
15   cout << "\nEOF in this system is: "<< c;
16   cout << "\nAfter input, cin.eof() is "<< cin.eof() << endl;
17   return 0;
18 }

输出结果:
Before input, cin.eof() is 0
Enter a sentence followed by end-of-file:
Testing the get and put member functions^z
Testing the get and put member functions
EOF in this system is: -1
After input cin.eof() is 1

                       图 11.12 使用成员函数get.put和eof

    带一个字符型参数的get成员函数自动读取输人流中的下一个字符(包括空白字符)。当遇到文件结束符时,该版本的函数返回0,否则返回对istream对象的引用,并用该引用再次调用get函数。
    带有三个参数的get成员函数的参数分别是接收字符的字符数组、字符数组的大小和分隔符(默认值为'\n')。函数或者在读取比指定的最大字符数少一个字符后结束,或者在遇到分隔符时结束。为使字符数组(被程序用作缓冲区)中的输入字符串能够结束,空字符会被插入到字符数组中。函数不把分隔符放到字符数组中,但是分隔符仍然会保留在输人流中。图11.13的程序比较了cin(与流读取运算符一起使用)和cin.get的输入结果。注意调用cin.get时未指定分隔符,因此用默认的'\n'。

1 // Fig. 11.13: figll 13.cpp
2 // contrasting input of a string with cin and cin.get.
3 #include <iostream.h>
4
5 int main()
6{
  const int SIZE = 80;
  char buffer1[ SIZE ], buffer2[ SIZE ] ;
9
10  cout << "Enter a sentence:\n";
11  cin >> buffer1;
12  cout << "\nThe string read with cin was:\n"
13       << buffer1 << "n\n";
14
15  cin.get( buffer2, SIZE );
16  cout << "The string read with cin.get was:\n"
17       << buffer2 << endl;
18
19  return 0;
20 }

输出结果:
Enter a sentence:
Contrasting string input with cin and cin.get
The string read with cin was:
Contrasting

The string read with cin.get was:
string input with cin and cin.get

                       图 11.13 比较用cin和cin.get输入的字符串的结果

    成员函数getline与带三个参数的get函数类似,它读取一行信息到字符数组中,然后插入一个空字符。所不同的是,getline要去除输入流中的分隔符(即读取字符并删除它),但是不把它存放在字符数组中。图11.14中的程序演示了用getline输入一行文本。
1 // Fig. 11.14: figll_14.cpp
2 // Character input with member function getline.
3 #include <iostream.h>
4
5 int main()
6{
  const SIZE = 80;
  char buffe[ SIZE ];
9
10  cout << "Enter a sentence:\n";
11  cin.getline( buffer, SIZE );
12
13  cout << "\nThe sentence entered is:\n" << buffer << endl;
14  return 0;
15 }

输出结果:
Enter a sentence:
Using the getline member function

The sentence entered is:
Using the getline member function

                               图 11.14 用成员函数getline输入字符

11.4.3  istream类中的其他成员函数(peek、putback和ignore)
    成员函数ignore用于在需要时跳过流中指定数量的字符(默认个数是1),或在遇到指定的分隔符(默认分隔符是EOF,使得ignore在读文件的时候跳过文件末尾)时结束。
    成员函数putback将最后一次用get从输人流中提取的字符放回到输入流中。对于某些应用程序.该函数是很有用的。例如,如果应用程序需要扫描输入流以查找用特定字符开始的域,那么当输入该字符时,应用程序要把该字符放回到输入流中,这样才能使该字符包含到要被输入的数据中。
    成员函数peek返回输入流中的下一个字符,但并不将其从输入流中删除。

11.4.4  类型安全的I/O
    C 提供类型安全的I/O。重载运算符<<和>>是为了接收指定类型的数据。如果接收了非法的数据类型,那么系统就会设置各种错误标志,用户可通过测试这些标志判断I/O操作的成功与失败。这种处理方法能够使程序保持控制权。11.8节要讨论这些错误标志。

11.5  成员函数read、gcount和write的无格式输入/输出
    调用成员函数read、write可实现无格式输入/输出。这两个函数分别把一定量的字节写入字符数组和从字符数组中输出。这些字节都是未经任何格式化的,仅仅是以原始数据形式输入或输出。
例如:
    char buffe[]  ="HAPPY BIRTHDAY";
    cout.write(buffer, 10  );
输出buffet的10个字节(包括终止cout和<<输出的空字符)。因为字符串就是第一个字符的地址,所以函数调用:
    cout.write("ABCDEFGHIJKLMNOPQRSTUVWXYZ",10);
显示了字母表中的前10个字母。
    成员函数read把指定个数的字符输入到字符数组中。如果读取的字符个数少于指定的数目,可以设置标志位failbit(见11.8节)。
    成员函数gcount统计最后输入的字符个数。
    图11.15中的程序演示了类istream中的成员函数read和gcount,以及类ostream中的成员函数write。程序首先用函数read向字符数组buffer中输入20个字符(输入序列比字符数组长),然后用函数gcount统计所输入的字符个数,最后用函数write输出buffer中的字符。

1 // Fig. 11.15: fig11_15.cpp
2 // Unformatted I/O with read, gcount and write.
3 #include <iostream.h>
4
5 int main()
6 {
  const int SIZE = 80;
  char buffer[ SIZE ];
9
10  cout << "Enter a sentence:\n";
11  cin.read( buffer, 20 );
12  cout << "\nThe sentence entered was:\n";
13  cout.write( buffer, cin.gcount() );
14  cout << endl;
15  return 0;
16 }

输出结果:
Enter a sentence:
Using the read, write, and gcount member functions
The sentence entered was:
Using the read,write

                            图 11.15 成员函数read,gcount和write的无格式I/O


11.6  流操纵算子:
   
C 提供了大量的用于执行格式化输入/输出的流操纵算子。流操纵算子提供了许多功能,如设置域宽、设置精度、设置和清除格式化标志、设置域填充字符、刷新流、在输出流中插入换行符并刷新该流、在输出流中插入空字符、跳过输入流中的空白字符等等。下面几节要介绍这些特征。

11.6.1  整数流的基数:流操纵算子dec、oct、hex和setbase
    整数通常被解释为十进制(基数为10)整数。如下方法可改变流中整数的基数:插人流操纵算子hex可设置十六进制基数(基数为16)、插人流操纵算子oct可设置八进制基数(基数为8)、插人流操纵算子dec可恢复十进制基数。
    也可以用流操纵算子setbace来改变基数,流操纵算于setbase带有一个整数参数10、8或16。因为流操纵算子setbase是带有参数的,所以也称之为参数化的流操纵算子。使用setbose或其他任何参数化的操纵算子都必须在程序中包含头文件iomanip.h。如果不明确地改变流的基数,流的基数是不变的。图11.16中的程序示范了流操纵算子hex、oct、dec和setbase的用法。
1 // Fig. 11.16: fig11_16.cpp
2 // Using hex, oct, dec and setbase stream manipulators.
3 #include <iostream.h>
4 #include <iomanip.h>
5
6 int main()
7{
  int n;
9
10  cout << "Enter a decimal number: ";
11  cin >> n;
12
13  cout << n << "in hexadecimal is:"
14      << hex << n << '\n'
15      << dec << n << "in octal is:"
16      << oct << n << '\n'
17      << setbase( 10 ) << n <<" in decimal is:"
18      << n << endl;
19
20  return 0;
21 }

输出结果:
Enter a decimal number: 20
20 in hexadecimal is: 14
20 in octal is: 24
20 in decimal is: 20
                                  
                             图 11.16 使用流操纵算子hex、oct、dec和setbase

11.6.2  设置浮点数精度(precision、setprecision)
    在C 中可以人为控制浮点数的精度,也就是说可以用流操纵算子setprecision或成员函数percision控制小数点后面的位数。设置了精度以后,该精度对之后所有的输出操作都有效,直到下一次设置精度为止。无参数的成员函数percision返回当前设置的精度。图11.17中的程序用成员函数precision和流操纵算子setprecision打印出了2的平方根表,输出结果的精度从0连续变化到9。
1 // Fig. 11.17: fig11_17.cpp
2 // Controlling precision of floating-point values
3 #include <iostream.h>
4 #include <iomanip.h>
5 #include <math.h>
6
7 int main()
8
  double root2 = sqrt( 2.0 );
10   int places;
11
12   cout << setiosflags(ios::fixed)
13       << "Square root of 2 with precisions 0-9.\n"
14       << "Precision set by the"
15       << "precision member function:" << endl;
16
17   for ( places = 0; places <= 9; places ) {
18     cout.precision( places );
19     cout << root2 << '\n';
20     }
21
22   cout << "\nPrecision set by the"
23       << "setprecision manipulator:\n";
24
25   for ( places = 0; places <= 9; places )
26     cout << setprecision( places ) << root2 << '\n';
27
28   return 0;
29 }

输出结果:
Square root of 2 with pzecisions 0-9.
Precision set by the precision member function:
1
1.4
1.41
1.414
1.4142
1.41421
1.414214
1.4142136
1.41421356
1.414213562
Precision set by the setprecision manipulator:
1
1.4
1.4l
1.414
1.4142
1.41421    ·
1.414214
1.4142136
1.41421356
1.414213562

                            图11.17  控制浮点数的精度

11.6.3  设置域宽(setw、width)
    成员函数ios.width设置当前的域宽(即输入输出的字符数)并返回以前设置的域宽。如果显示数据所需的宽度比设置的域宽小,空位用填充字符填充。如果显示数据所需的宽度比设置的域宽大,显示数据并不会被截断,系统会输出所有位。

    常见编程错误11.4
    域宽设置仅对下一行流读取或流插入操作有效,在一次操作完成之后,城宽又被置回0,也就是输出值按照所需要的宽度来输出。不带参数的width函数返回当前域宽。认为域宽设置适用于所有输出走十逻辑错误。

    常见编程错误11.5
    未对所处理的输出数据提供足够的域宽时,输出数据将按需要的域宽进行输出,有可能产生难以阅读的输出结果。

    图1l.18中的程序示范了成员函数width的输入和输出操作。注意,输入操作提取字符串的最大宽度比定义的域宽小1,这是因为在输入的字符串后面必须加上一个空字符。当遇到非前导空白字符时,流读取操作就会终止。流操纵算子setw也可以用来设置域宽。注意:提示用户输入时,用户应输入一行文本并按Enter键加上文件结束符(<ctrl>-z对于IDMPC兼容系统;<ctrl>-d对于UNIX与Macintosh系统)。
1 // fig11_18.cpp
2 // Demonstrating the width member function
3 #include <iostream.h>
4
5 int main()
6{
  int w = 4;
  char string[ 10 ];
9
10  cout << "Enter a sentence:\n";
11  cin.width( 5 );
12
13  while (cin >> string ) {
14     cout.width( w );
15     cout << string << endl;
16     cin.width( 5 );
17   }
18
19   return 0;
20 }

输出结果:
Enter a sentence:
This is a test of the width member function
This
       is
         a
       test
          of
          the
          widt
              h
            memb
               er
              func
               tion

                             图 11.18 演示成员函数width


11.6.4  用户自定义的流操纵算子
    用户可以建立自己的流操纵算子。图11.19中的程序说明了如何建立和使用新的流操纵算子bell、ret、tab和endline。用户还可以建立自己的带参数的流操纵算子,这方面内容可参看系统的手册。
1 /! Fig. 11.19: fig11_19.cpp
2 // Creating and testing user-defined, nonparameterized
3 // stream manipulators.
4 #include <iostream.h>
5
6 // bell manipulator (using escape sequence \a)
7 ostream& bell( ostream& output ) { return output << '\a'; }
8
9 // ret manipulator (using escape sequence \r)
10 ostream& ret( ostream& output ) ( return output << '\r'; }
11
12 // tab manipulator (using escape sequence \t)
13 ostream& tab( ostream& output ) { return output << '\t'; ]
14
15 // endLine manipulator (using escape sequence \n
16 // and the flush member function)
17 ostream& endLine( ostream& output )
18 {
19   return output << '\n' << flush;
20 }
21
22 int main()
23 {
24   cout << "Testing the tab manipulator:" << endLine
25       << 'a' << tab << 'b' << tab << 'c' << endLine
26       << "Testing the ret and bell manipulators:"
27       << endLine << "..........  ";
28   cout << bell;
29   cout << ret <<  .........  << endLine;
30   return 0;
31 }

输出结果:
Testing the tab manipulator:
       c
Testing the ret and bell manipulators:
--------........

0

阅读 评论 收藏 转载 喜欢 打印举报/Report
  • 评论加载中,请稍候...
发评论

    发评论

    以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

      

    新浪BLOG意见反馈留言板 电话:4000520066 提示音后按1键(按当地市话标准计费) 欢迎批评指正

    新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 会员注册 | 产品答疑

    新浪公司 版权所有