C++cout格式化输出(转)
这篇⽂章主要讲解如何在C++中使⽤cout进⾏⾼级的格式化输出操作,包括数字的各种计数法(精度)输出,左或右对齐,⼤⼩写等等。通过本⽂,您可以完全脱离scanf/printf,仅使⽤cout来完成⼀切需要的格式化输⼊输出功能(从⾮性能的⾓度⽽⾔)。更进⼀步⽽⾔,您还可以在<sstream>、<fstream>上使⽤这些格式化操作,从⽽代替sprintf和fprintf函数。为⽅便描述,下⽂仅以cout为例进⾏介绍。
⼀、综述
cout是STL库提供的⼀个iostream实例,拥有ios_base基类的全部函数和成员数据。进⾏格式化操作可以直接利⽤setf/unsetf函数和flags函数。cout维护⼀个当前的格式状态,setf/unsetf函数是在当前的格式状态上追加或删除指定的格式,⽽flags则是将当前格式状态全部替换为指定的格式。cout为这个函数提供了如下参数(可选格式):
ios::dec 以10进制表⽰整数
ios::hex 以16进制表⽰整数
ios::oct 以8进制表⽰整数
ios::showbase 为整数添加⼀个表⽰其进制的前缀
ios::internal 在符号位和数值的中间插⼊需要数量的填充字符以使串两端对齐
ios::left 在串的末尾插⼊填充字符以使串居左对齐
ios::right 在串的前⾯插⼊填充字符以使串居右对齐
ios::boolalpha 将bool类型的值以true或flase表⽰,⽽不是1或0
ios::fixed 将符点数按照普通定点格式处理(⾮科学计数法)
ios::scientific 将符点数按照科学计数法处理(带指数域)
ios::showpoint 在浮点数表⽰的⼩数中强制插⼊⼩数点(默认情况是浮点数表⽰的整数不显⽰⼩数点)
ios::showpos 强制在正数前添加+号
ios::skipws 忽略前导的空格(主要⽤于输⼊流,如cin)
ios::unitbuf 在插⼊(每次输出)操作后清空缓存
ios::uppercase 强制⼤写字母
以上每⼀种格式都占⽤独⽴的⼀位,因此可以⽤“|”(位或)运算符组合使⽤。调⽤setf/unsetf或flags设置格式⼀般按如下⽅式进⾏:
cout.setf(ios::right | ios::hex); //设置16进制右对齐
cout.setf(ios::right, ios::adjustfield); //取消其它对齐,设置为右对齐
setf可接受⼀个或两个参数,⼀个参数的版本为设置指定的格式,两个参数的版本中,后⼀个参数指定了删除的格式。三个已定义的组合格式为:
ios::adjustfield 对齐格式的组合位
ios::basefield 进制的组合位
ios::floatfield 浮点表⽰⽅式的组合位
设置格式之后,下⾯所有使⽤cout进⾏的输出都会按照指定的格式状态执⾏。但是如果在⼀次输出过程中需要混杂多种格式,使⽤cout的成员函数来处理就显得很不⽅便了。STL另提供了⼀套<iomanip>库可以满⾜这种使⽤⽅式。<iomanip>库中将每⼀种格式的设置和删除都进⾏了函数级的同名封装,⽐如fixed函数,就可以将⼀个ostream的对象作为参数,在内部调⽤setf函数对其设置ios::fixed格式后再
返回原对象。此外<iomanip>还提供了setiosflags、setbase、setfill、setw、setprecision等⽅便的格式控制函数,下⽂会逐⼀进⾏介绍。⼤多数⽰例代码都会使⽤到<iomanip>,因此默认包含的头⽂件均为:
#include <iomanip>
#include <iostream>
⼆、缩进
将输出内容按指定的宽度对齐,需要⽤到ios::right、ios::left、ios::internal和iomanip⾥的setw。其中setw⽤于指定要输出内容的对齐宽度。以下两段代码的结果完全相同,前⾯是⼀个浮点数-456.98,后⾯紧跟着⼀个字符串“The End”以及换⾏符“endl”。
代码⼀:
#include <iomanip>
#include <iostream>
using namespace std;
int main(void) {
cout.flags(ios::left); //左对齐
cout << setw(10) << -456.98 << "The End" << endl;
cout.flags(ios::internal); //两端对齐
cout << setw(10) << -456.98 << "The End" << endl;
cout.flags(ios::right); //右对齐
cout << setw(10) << -456.98 << "The End" << endl;
return0;
}
代码⼆:
#include <iomanip>
#include <iostream>
using namespace std;
int main(void) {
cout << left << setw(10) << -456.98 << "The End" << endl; //左对齐
cout << internal << setw(10) << -456.98 << "The End" << endl; //两端对齐
cout << right << setw(10) << -456.98 << "The End" << endl; //右对齐
return0;
}
结果:
-456.98 The End
- 456.98The End
-
456.98The End
这⾥要额外说明的⼀点是,setw函数会⽤当前的填充字符控制对齐位置,默认的填充字符是空格。可以通过<iomanip>的setfill来设置填充字符,⽐如下⾯的代码⽤字符“0”作为填充字符:
#include <iomanip>
#include <iostream>
using namespace std;
int main(void) {
cout << setfill('0') << setw(10) << 45698 << endl;
return0;
}
结果:
0000045698
三、整数
输出整数的格式有按不同进制数出:ios::hex(16进制)、ios::dec(10进制)、ios::oct(8进制),也可强制其输出符号(正数也加
上“+”号前缀),对于16进制的输出还可配合ios::uppercase使所有字母以⼤写表⽰。代码⽰例如下:
cout.setf(ios::showpos | ios::uppercase);
cout << hex << setw(4) << 12 << setw(12) << -12 << endl;
cout << dec << setw(4) << 12 << setw(12) << -12 << endl;
cout << oct << setw(4) << 12 << setw(12) << -12 << endl;
cout.unsetf(ios::showpos | ios::uppercase);
cout << hex << setw(4) << 12 << setw(12) << -12 << endl;
cout << dec << setw(4) << 12 << setw(12) << -12 << endl;
cout << oct << setw(4) << 12 << setw(12) << -12 << endl;
return0;
}
结果:
C FFFFFFF4
+12 -12
14 37777777764
c fffffff4
12 -12
14 37777777764
利⽤<iomanip>的setbase函数同样可以设置整数的三种进制,参数分别为8、10和16,但使⽤起来⽐上⾯的⽅法还更复杂⼀些,除⾮是特殊的代码规范要求(有些规范要求避免将常量直接作为表达式),⼀般不建议使⽤setbase。此外,还可以利⽤ios::showbase来为整数的前⾯加⼀个表⽰进制的
前缀,代码如下:
#include <iomanip>
#include <iostream>
using namespace std;
int main(void) {
cout << showbase << setw(4) << hex << 32 << setw(4) << oct << 32 << endl;
cout << noshowbase << setw(4) << hex << 32 << setw(4) << oct << 32 << endl;
return0;
}
结果:
0x20 040
20 40
上⾯代码中的showbase/noshobase也可以⽤cout的setf来代替,其结果是完全相同的:
#include <iomanip>
#include <iostream>
using namespace std;
int main(void) {
cout.setf(ios::showbase);
cout << setw(4) << hex << 32 << setw(4) << oct << 32 << endl;
cout.unsetf(ios::showbase);
cout << setw(4) << hex << 32 << setw(4) << oct << 32 << endl;
return0;
}
四、⼩数
⼩数可分为两种格式类型,⼀种是定点表⽰“ios::fixed”(不带指数域),另⼀种是科学计数法表⽰“ios::scientific”(带指数域)。与<iomanip>的setprecision配合使⽤,可以表⽰指定⼩数点后⾯的保留位数(四舍五⼊)。⽰例代码如下:
cout.setf(ios::fixed);
cout << setprecision(0) << 12.05 << endl;
cout << setprecision(1) << 12.05 << endl;
ios 12.1cout << setprecision(2) << 12.05 << endl;
cout << setprecision(3) << 12.05 << endl;
cout.setf(ios::scientific, ios::floatfield);
cout << setprecision(0) << 12.05 << endl;
cout << setprecision(1) << 12.05 << endl;
cout << setprecision(2) << 12.05 << endl;
cout << setprecision(3) << 12.05 << endl;
return0;
}
结果:
12
12.1
12.05
12.050
1.205000e+001
1.2e+001
1.21e+001
1.205e+001
需要注意的是,有时会因为机器的精度问题导致四舍五⼊的结果不正确。这种问题⼀般需要⼿动修正,见如下代码⽰例:
#include <iomanip>
#include <iostream>
using namespace std;
int main(void) {
cout << fixed << setprecision(1) << 2.05 << endl;
cout << fixed << setprecision(1) << 2.05 + 1e-8 << endl;
return0;
}
结果:
2.0
2.1
五、字符串
字符串的输出处理主要是对齐,这⼀点在第⼆部分已经介绍过了,下⾯主要介绍字符串的输⼊⽅法。为了⽅便起见,我们使⽤<string>库。在输⼊字符串时,可以利⽤<string>库提供的getline函数读取整⾏数据。getline函数有两个版本,第⼀个版本有两个参数,第⼀个参数指定输⼊流(⽐如cin),第⼆个参数指定⼀个string对象。getline会读取屏幕上输⼊的字符,直到遇到换⾏符“\n”为⽌;第⼆个版本有三个参数,前两个与第⼀个版本相同,第三个参数为指定的结束字符。注意,getline不会读⼊默认或指定的结束字符,但在调⽤之后读取的位置已经跳过结束字符。调⽤⽰例代码如下:
#include <string>
using namespace std;
int main(void) {
string str1, str2;
getline(cin, str1);
cin >> str2;
cout << str1 << endl << str2 << endl;
return0;
}
输⼊:
abc
abc
结果:
abc
abc
六、缓冲区
由于调⽤系统函数在屏幕上逐个显⽰字符是很慢的,因此cin/cout为了加快速度使⽤缓冲区技术,粗略的讲就是暂时不输出指定的字符,⽽是存放在缓冲区中,在合适的时机⼀次性输出到屏幕上。如果单纯使⽤C++的输⼊/输出流来操作字符是不存在同步的问题的,但是如果要和C标准库的stdio库函数混合使⽤就必须要⼩⼼的处理缓冲区了。如果要与scanf和printf联合使⽤,务必在调⽤cout前加上
cout.sync_with_stdio(),设置与stdio同步,否则输出的数据顺序会发⽣混乱。
flush和endl都会将当前缓冲区中的内容⽴即写⼊到屏幕上,⽽unitbuf/nounitbuf可以禁⽌或启⽤缓冲区。⽰例代码如下:
#include <iomanip>
#include <iostream>
using namespace std;
int main(void) {
cout << 123 << flush << 456 << endl;
cout << unitbuf << 123 << nounitbuf << 456 << endl;
return0;
}
结果:
123456
123456
七、综合使⽤
⽰例代码:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论