11 }
输出结果:
Welcome to C++!
图 3.4 用两条流插入语句输出字符串
也可以用流操纵算子endl(行结束)实现转义序列\\n(换行符)的功能(见图3.5)。流操纵算子endl发送一个换行符并刷新输出缓冲区(不管输出缓冲区是否已满都把输出缓冲区中的内容立即输出)。也可以用下面的语句刷新输出缓冲区: cout << flush;
3.6节要详细讨论流操纵算子。
1 // Fig. 3.5: fig11_05.cpp
2 // Using the endl stream manipulator. 3 #include
7 cout << \8 cout << \
9 cout << endl; // end line stream manipulator 10
11 return 0; 12 }
输出结果:
Welcome to C++!
图 3.5 使用流操纵算子endl
流插入运算符还可以输出表达式的值(见图3.6)
1 // Fig. 3.6: fig11_O6.cpp
2 // Outputting expression values. 3 #include
7 cout << \8
9 // parentheses not needed; used for clarity 10 cout << ( 47 + 53 ); // expression 11 cout << endt;
-36-
12
13 return O; 14 }
输出结果: 47 plus 53 is 100
图 3.6 输出一个表达式的值
3.3.2 连续使用流插入/流读取运算符
重载的运算符<<和>>都可以在一条浯句中连续使用(见图3.7)。 1 file:// Fig.3.7: fig11_07.cpp
2 file:// Cascadlng the overlOadGd << OPeratOr. 3 #includc
5 int main() 6 {
7 cout << \ 8
9 return O; 10 }
输出结果: 47 plus 53 is 100
图 3.7 连续使用重载运算符<<
图中多次使用流插入运算符的语句等同于下面的语句: ((( cout << \
之所以可以使用这种写法,是因为重载的运算符<<返回了对其左操作数对象(即cout)的引用,因此最左边括号内的表达式: ( cout << \
它输出一个指定的字符串,并返回对cout的引用,因而使中间括号内的表达式解释为: ( cout << ( 47 + 53 ) )
它输出整数值100,并返回对cout的引用。于是最右边括号内的表达式解释为: cout << endl;
它输出一个换行符,刷新cout并返回对cout的引用。最后的返回结果未被使用。
3.3.3 输出char*类型的变量
C语言式的I/O必须要提供数据类型信息。C++对此作了改进,能够自动判别数据类型。但
-37-
是,C++中有时还得使用类型信息。例如,我们知道字符串是char*类型,假定需要输出其指针的值,即字符串中第一个字符的地址,但是重载运算符<<输出的只是以空(null)字符结尾的char*类型的字符串,因此使用void*类型来完成上述需求(需要输出指针变量的地址时都可以使用void*类型)。图3.8中的程序演示了如何输出char*类型的字符串及其地址,辅出的地址是用十六进制格式表示。在C++中,十六进制数以0x或0X打头,3.6.1节、3.7.4节、3.7.5节和3.7.7节要详细介绍控制数值基数的方法。 1 // Fig. 3.8: fig11_08.cpp
2 // Printing the address stored in a char* variable 3 #include
7 char *string = \8
9 cout << \
10 << \11 << static_cast< void*>( string )< 输出结果: Value of string is:test Value of staticcast 图 3.8 输出char*类型变量的地址 3.3.4 用成员函数put输出字符和put函数的连续调 用put成员函数用于输出一个字符,例如语句: cout.put('A'); 将字符A显示在屏幕上。 也可以像下面那样在一条语句中连续调用put函数: cout.put('A').put('\\n'); 该语句在输出字符A后输出一个换行符。和<<一样,上述语句中圆点运算符(.)从左向右结合,put 成员函数返回调用put的对象的引用。还可以用ASCII码值表达式调用put函数,语句cout.put(65)也 输出字符A。 -38- 3. 4 输入流 下面我们要讨论流的输入,这是用流读取运算符(即重载的运算符>>)实现的。流读取运算符通常会跳过输人流中的空格、tab键、换行符等等的空白字符,稍后将介绍如何改变这种行为。当遇到输入流中的文件结束符时,流读取运算符返回0(false);否则,流读取运算符返回对调用该运算符的对象的引用。每个输入流都包含一组用于控制流状态(即格式化、出错状态设置等)的状态位。当输入类型有错时,流读取运算符就会设置输人流的failbit状态位;如果操作失败则设置badbit状态位,后面会介绍如何在I/O操作后测试这些状态位。3.7节和3.8节详细讨论了流的状态位。 3.4.1 流读取运算符 图3.9中的范例程序用cin对象和重载的流读取运算符>>读取了两个整数。注意流读运算符可以连续使用。 1 // Fig. 3.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 8 int x, y; 9 10 cout << \11 cin >> x >> y; 12 cout << \13 << ( x + y ) << endl; 14 15 return 0; 16 } 输出结果: Enter two integers: 30 92 Sum of 30 and 92 is: 122 图 3.9 计算用cin和流读取运算符从键盘输入的两个整数值的和 如果运算符>>和<<的优先级相对较高就会出现问题。例如,在图3.10的程序中,如果条件表达式没有用括号括起来,程序就得不到正确的编译(学员可以试一下)。 1 // Fig. 3.10: figlll0.cpp 2 // Avoiding a precedence problem between the stream-insertion 3 // operator and the conditional operator. -39- 4 // Need parentheses around the conditional expression. 5 #include 9 int x, y; 10 11 cout << \12 cin >> x >> y; 13 cout << x << ( x == y ? \14 << \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 图 3.10 避免在流插入运算符和条件运算符之间出现优先级错误 我们通常在while循环结构的首部用流读取运算符输入一系列值。当遇到文件结束符时,读取运算符返回0false)。图3.11中的程序用于查找某次考试的最高成绩。假定事先不知道有多少个考试成绩,并且用户会输入表示成绩输入完毕的文件结束符。当用户输入文件结束符时,while循环结构中的条件(cin>>grade)将变为0(即false)。 在图3. 11中,cin>>grade可以作为条件,因为基类ios(继承istream的类)提供一个重载的强制类型转换运算符,将流变成void*类型的指针。如果读取数值时发生错误或遇到文件结束符,则指针值为0。编译器能够隐式使用void*类型的强制转换运算符。 1 // Fig. 3.11: figll_ll.cpp 2 // Stream-extraction operator returning false on end-of-file. 3 #include 7 int grade, highestGrade = -1; 8 9 cout << \10 while ( cin >> grade){ 11 if ( grade > highestGrade ) -40-