四、格式化输入输出 C++语言中有两种方法可以控制格式化输入输出:流对象的成员函数和操纵器。 <1> 流对象的成员函数 下表中的格式化标志,可以通过成员函数setf()来设置,也可以用unsetf()来复位,如果需要设置多个标志,可以使用 | 运算符(使用标志时前边加上ios::)。───────┬───────────────────────┬──── 格式化标志 │ 描 述 │ 默 认───────┼───────────────────────┼──── boolalpha │ 以alpha格式进行布尔输入输出 │ off showbase │ 显示8进制或16进制前缀 │ off showpoint │ 显示10进制浮点数末尾的零 │ off showpos │ 正数时显示加号 │ off skipws │ 跳过输入中的空白字符 │ on uppercase │ 十六进制显示大写0X和A~F,科学计数显示大写E │ off unitbuf │ 启用单元缓冲 │ off───────┴───────────────────────┴──── 除了setf()和unsetf()外,常用的成员函数还有:用于设置浮点值显示精度的precision(),注意显示精度包括整数位和小数位;用于设置输出宽度的width(),注意每次输出都需要重新设定输出宽度;用于设置填充字符的fill(),当前设定会保持直到下一次更改填充字符。 下面的程序给出了上述成员函数的使用示例:// ----- Prog01-04.cpp -------------------------------------------------// 功能:流对象的成员函数使用示例#include <iostream>using namespace std;int main(){ bool b = true; cout << b << '\n'; // 显示为布尔型 cout.setf(ios::boolalpha); cout << b << '\n'; double x = 12345.6789, y = 12345; cout << x << ' ' << y << '\n'; // 设定显示精度 cout.precision(11); cout << x << ' ' << y << '\n'; // 显示末尾的零 cout.setf(ios::showpoint); cout << x << ' ' << y << '\n'; // 显示正数的符号 cout.setf(ios::showpos); cout << x << ' ' << y << '\n'; // 恢复符号和显示精度设定 cout.unsetf(ios::showpos); cout.precision(6); // 使用科学计数法 double z = 1234567890.123456; cout.setf(ios::scientific, ios::floatfield); cout << z << '\n'; cout.setf(ios::uppercase); cout << z << '\n'; // 设置输出宽度 cout << '|'; cout.width(10); cout << "hello" << '|' << '\n'; // 设置填充字符 cout << '|'; cout.fill('#'); cout.width(10); cout << "hello" << '|' << '\n'; system("pause"); return 0;}// --------------------------------------------------------------------- 有一些格式化选项可以具有一定范围的值,例如:用来确定显示整型数基数的ios:basefield可以被设置成10进制、8进制或16进制,由于这些是位域而不是单个的位,可以用带两个参数形式的setf()来设置。───────────┬────────────────────┬─── 域 │ 描 述 │默认值───────────┼────────────────────┼─── adjustfied (调整域) │left, right, internal (左、右、内部) │right basefield (基数域) │dec, oct, hex (十进制、八进制、十六进制)│dec floatfield (浮点域) │fixed, scientfic (定点、科学计数法) │fixed───────────┴────────────────────┴─── 下面的示例程序演示了格式化域的用法:// ----- Prog01-05.cpp -------------------------------------------------// 功能:在不同基数下显示整数(使用setf)#include <iostream>using namespace std;int main(){ int x, y, z; cout << "请输入三个整数: "; cin >> x >> y >> z; cout << x << ',' << y << ',' << z << endl; // 在不同基数下显示 cout << x << ','; cout.setf(ios::oct, ios::basefield); cout << y << ','; cout.setf(ios::hex, ios::basefield); cout << z << endl; // 显示基数前缀 cout.setf(ios::showbase); cout.setf(ios::dec, ios::basefield); cout << x << ','; cout.setf(ios::oct, ios::basefield); cout << y << ','; cout.setf(ios::hex, ios::basefield); cout << z << endl; system("pause"); return 0;}// --------------------------------------------------------------------- <2> 操纵器 当标识符endl出现在一个输出流中时,一个换行字符就被插入并且流被刷新,endl是操纵器的一个例子,即为了副效应而插入到流的一个对象。在 <iostream>中被声明的系统预定义的操纵器列于下表,使用操纵器来代替显式调用setf函数,可以使代码更为高效。 简单的操纵器( <iostream> )──────────┬──────────────┬────────── 操 纵 器 │ 等价的 setf() 函数 │ 描 述──────────┼──────────────┼────────── [fmt flags Group] │ │ boolalpha │setf(boolalpha) │显示布尔型 noboolalpha │unsetf(boolalpha) │显示非布尔型 showbase │setf(showbase) │显示基数前缀 noshowbase │unsetf(showbase) │不显示基数前缀 showpoint │setf(showpoint) │显示小数点 noshowpoint │unsetf(showpoint) │不显示小数点 showpos │setf(showpos) │显示正数的符号 noshowpos │unsetf(showpos) │不显示正数的符号 skipws │setf(skipws) │跳过输入中的空白 noskipws │unsetf(skipws) │不跳过输入中的空白 uppercase │setf(uppercase) │显示为大写 nouppercase │unsetf(uppercase) │显示为小写 unitbuf │setf(unitbuf) │单元缓冲 ununitbuf │unsetf(unitbuf) │全缓冲──────────┼──────────────┼────────── [adjustfield Group]│ │ left │setf(left, adjustfield) │左对齐 right │setf(right, adjustfield) │右对齐 internal │setf(internal, adjustfield) │内部对齐──────────┼──────────────┼────────── [basefield Group] │ │ dec │setf(dec, basefield) │十进制 oct │setf(oct, basefield) │八进制 hex │setf(hex, basefield) │十六进制──────────┼──────────────┼────────── [floatfield Group] │ │ fixed │setf(fixed, floatfield) │定点 scientific │setf(scientific, floatfield)│科学计数法──────────┼──────────────┼────────── [other] │ │ endl │ │插入一个换行符并刷新 ends │ │插入一个空字符 flush │ │强制刷新一个流──────────┴──────────────┴────────── 下面的示例程序与Prog01-05.cpp功能完全相同,但代码更为精简和清晰。// ----- Prog01-06.cpp -------------------------------------------------// 功能:在不同基数下显示整数(使用操纵器)#include <iostream>using namespace std;int main(){ int x, y, z; cout << "请输入三个整数: "; cin >> x >> y >> z; cout << x << ',' << y << ',' << z << endl; // 在不同基数下显示 cout << dec << x << ',' << oct << y << ',' << hex << z << endl; // 显示基数前缀 cout << showbase; cout << dec << x << ',' << oct << y << ',' << hex << z << endl; system("pause"); return 0;}// --------------------------------------------------------------------- 在 <iomanip> 中声明了一些带有参数的操纵器,现列于下表, 使用的时候要在程序头部加上#include <iomanip>指令。需要注意的是,ios::width域是特殊的,它在每次插入后立即重置为0,因此操纵器setfill()与成员函数fill()一样,设定一次只影响输出序列里紧邻的那个对象的打印格式。 参数化的操纵器( <iomanip> )──────────┬───────────────────────── 操 纵 器 │ 描 述──────────┼───────────────────────── setioflags(n) │ 设置所有 n 所设置的标志 resetioflags(n) │ 复位所有 n 所设置的标志 setbase(n) │ 等同于: setf(n, ios::basefield) setprecision(n) │ 等同于: precision(n) setw(n) │ 等同于: width(n) setfill(n) │ 等同于: fill(c)──────────┴───────────────────────── 下面的程序演示了对齐方式与字符填充的显示效果。内部对齐(internal)是比较令人困惑的对齐方式,显示的时候如果宽度较大, 会在数值与前导符号(+ / -)或者基数标志(0 / 0x)之间插入填充符号,以下面的程序为例,输出宽度为10字符,用内部对齐方式输出 -12.345 的结果是:|- 12.345|// ----- Prog01-07.cpp -------------------------------------------------// 功能:对齐方式与字符填充的显示效果示例#include <iostream>#include <iomanip>using namespace std;int main(){ double x = -12.345; // 对齐方式 cout << '|' << setw(10) << x << '|' << endl; cout << left << '|' << setw(10) << x << '|' << endl; cout << right << '|' << setw(10) << x << '|' << endl; cout << internal << '|' << setw(10) << x << '|' << endl; // 字符填充 cout << right << '|' << setw(10) << "hello" << '|' << endl; cout.fill('#'); cout << '|' << setw(10) << "hello" << '|' << endl; system("pause"); return 0;}// --------------------------------------------------------------------- >> 关于风格 格式化输入输出中,操纵器可以使代码更加精简,阅读起来也更为清晰,例如Prog01-04.cpp与Prog01-07.cpp中功能相同的两段代码: // ====== Prog01-04.cpp代码片段 ====== cout << '|'; cout.width(10); cout << "hello" << '|' << '\n'; cout << '|'; cout.fill('#'); cout.width(10); cout << "hello" << '|' << '\n'; // ====== Prog01-07.cpp代码片段 ====== cout << right << '|' << setw(10) << "hello" << '|' << endl; cout.fill('#'); cout << '|' << setw(10) << "hello" << '|' << endl; 很明显第一段代码显得冗长,可读性不高, 这是因为语句 cout.width(10);切断了输出流序列,而操纵符setw()则可以像输出对象一样插入到输出流序列中去。但如果用 ...<<setfill('#')<<... 代替 cout.fill('#'); 来设置填充字符, 反倒会显得不是很自然,因为填充字符设置之后会保持下去,插入在输出流中不容易直接看明白它的效果。

评论