You are on page 1of 8

cin 和 cout 等格式化输入输出库函数的说明和使用

一、综述
需要注意的是: 如果使用了控制符,在程序单位的开头除了要加 iostream 头文件外,还
要加 iomanip 头文件。下面是一些常用的格式化控制符。

控制符 作 用

dec 设置数值的基数为 10

hex 设置数值的基数为 16

oct 设置数值的基数为 8

setfill(c) 设置填充字符 c,c 可以是字符常量或字符变量

设置浮点数的精度为 n 位。在以一般十进制小数形式输出
setprecision(n) 时,n 代表有效数字。在以 fixed(固定小数位数)形式和
scientific(指数)形式输出时,n 为小数位数

setw(n) 设置字段宽度为 n 位

setiosflags( ios::fixed) 设置浮点数以固定的小数位数显示

setiosftags( ios::scientific) 设置浮点数以科学记数法(即指数形式)显示

在浮点数表示的小数中强制插入小数点(默认情况是浮点数
setiosftags( ios::showpoint)
表示的整数不显示小数点)

setiosflags( ios::left) 输出数据左对齐

setiosflags( ios::right) 输出数据右对齐

setiosflags( ios:: internal) 输出数据两端对齐

setiosflags( ios::skipws) 忽略前导的空格(主要用于输入流,如 cin)

setiosflags( ios::uppercase) 数据以十六进制形式输出时字母以大写表示

setiosflags( ios::lowercase) 数据以十六进制形式输出时宇母以小写表示


setiosflags(ios::showpos) 输出正数时强制在正数前给出“+”号

setiosflags(ios:: showbase) 为整数添加一个表示其进制的前缀

setiosflags(ios:: boolalpha) 将 bool 类型的值以 true 或 flase 表示,而不是 1 或 0

setiosflags(ios:: unitbuf) 在插入(每次输出)操作后清空缓存

以上每一种格式都占用独立的一位,因此可以用“|”(位或)运算符组合
使用。调用 setf/unsetf 或 flags 设置格式一般按如下方式进行:

 cout.setf(ios::right | ios::hex); //设置 16 进制右对齐


 cout.setf(ios::right, ios::adjustfield); //取消其它对齐,设置为右对齐
setf 可接受一个或两个参数,一个参数的版本为设置指定的格式,两个参数
的版本中,后一个参数指定了删除的格式。三个已定义的组合格式为:

 ios::adjustfield 对齐格式的组合位
 ios::basefield 进制的组合位
 ios::floatfield 浮点表示方式的组合位

二、缩进
将输出内容按指定的宽度对齐,需要用到 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;
return 0;
}
代码二:

#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; //右对齐
return 0;
}

结果:
-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;
return 0;
}

结果:0000045698

三、整数
输出整数的格式有按不同进制数出:ios::hex(16 进制)、ios::dec(10 进
制)、ios::oct(8 进制),也可强制其输出符号(正数也加上“+”号前缀),
对于 16 进制的输出还可配合 ios::uppercase 使所有字母以大写表示。代码示例如
下:
#include <iomanip>
#include <iostream>
using namespace std;
int main(void) {
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;
return 0;
}
结果:
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;
return 0;
}
结果:
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;
return 0;
}

四、小数
小数可分为两种格式类型,一种是定点表示“ios::fixed”(不带指数域),
另一种是科学计数法表示“ios::scientific”(带指数域)。与<iomanip>的
setprecision 配合使用,可以表示指定小数点后面的保留位数(四舍五入)。示
例代码如下:
#include <iomanip>
#include <iostream>
using namespace std;
int main(void) {
cout.setf(ios::fixed);
cout << setprecision(0) << 12.05 << endl;
cout << setprecision(1) << 12.05 << endl;
cout << 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;
return 0;
}
结果:
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;
return 0;
}
结果:
2.0
2.1

四、字符串
字符串的输出处理主要是对齐,这一点在第二部分已经介绍过了,下面
主要介绍字符串的输入方法。为了方便起见,我们使用<string>库。在输入字符
串时,可以利用<string>库提供的 getline 函数读取整行数据。getline 函数有两个
版本,第一个版本有两个参数,第一个参数指定输入流(比如 cin),第二个参
数指定一个 string 对象。getline 会读取屏幕上输入的字符,直到遇到换行符“\
n”为止;第二个版本有三个参数,前两个与第一个版本相同,第三个参数为指
定的结束字符。注意,getline 不会读入默认或指定的结束字符,但在调用之后
读取的位置已经跳过结束字符。调用示例代码如下:
#include <iomanip>
#include <iostream>
#include <string>
using namespace std;
int main(void) {
string str1, str2;
getline(cin, str1);
cin >> str2;
cout << str1 << endl << str2 << endl;
return 0;
}
输入:
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;
return 0;
}
结果:
123456
123456

六、综合使用
示例代码:
#include <iomanip>
#include <iostream>
#include <string>
using namespace std;
struct COMMODITY { string Name; int Id; int Cnt; double Price; };
int main(void) {
COMMODITY cmd[] = {
{"Fruit", 0x101, 50, 5.268},
{"Juice", 0x102, 20, 8.729},
{"Meat", 0x104, 30, 10.133},
};
cout << left << setw(8) << "NAME" << right << setw(8) << "ID";
cout << right << setw(8) << "COUNT" << right << setw(8) << "PRICE" << endl;
for (int i = 0; i < sizeof(cmd) / sizeof(cmd[0]); ++i) {
cout << left << setw(8) << cmd[i].Name;
cout << right << hex << showbase << setw(8) << cmd[i].Id;
cout << dec << noshowbase << setw(8) << cmd[i].Cnt;
cout << fixed << setw(8) << setprecision(2) << cmd[i].Price << endl;
}
return 0;
}
结果:
NAME ID COUNT PRICE
Fruit 0x101 50 5.27
Juice 0x102 20 8.73
Meat 0x104 30 10.13

You might also like