cout格式化输出

原文链接:cout格式化输出

1. 修改显示时使用的计数系统(如int型使用八/十/十六进制显示)

ostream类是从ios类派生而来,ios类是从ios_base类派生而来。ios_base类存储了描述格式状态的信息,例如一个类成员中某些位决定使用哪个计数系统(如八/十/十六进制),另外一个成员决定字段的宽度,且ios_baseostream间接基类,因此ostream也可以修改计数系统和字段宽度。

对于设置显示整数的计数系统整数,我们使用dechexoct控制符来控制整数是以十进制、十六进制还是八进制显示。例如:

int n = 13;
hex(cout);  //控制符实际上是函数但不是成员函数,因此不必通过对象来调用,也可以使用cout << hex;
cout << n;  //输出d
cout << hex;//等同hex(cout)
cout << n;  //输出d
cout << oct;//等同oct(cout),将输出显示设置为八进制
cout << n;  // 输出15
cout << dec << n;//输出13
2. 调整字段宽度

ostream使用width()成员函数将长度不同的数字放到宽度相同的字段中,该方法的原型如下:

int width(); //该方法返回字段宽度的当前设置
int width(int i); //该方法将字段宽度设置为i个空格,并返回以前的字段宽度值。这样使得能够保存以前的值,以便以后恢复宽度值使用

width()方法只影响将显示的下一个项目,然后字段的宽度将恢复为默认值。例如:

cout << "字段默认宽度:" << cout.width() << endl;
cout << "12345" << endl;//显示12345,方便查看后面每个对象显示的时候占用的宽度
cout.width(3);//将字段宽度设置为3
cout << 'a' << 'b' << 'c' << endl;
cout.width(2);
cout << "aaa";//测试当字节宽度设置过小,是否影响显示,该语句执行后字符宽度将恢复为默认值0
auto i = cout.width(3);//i=0
auto j = cout.width(4);//由于上一个语句已经将宽度设置为3,因此j=3
auto k = cout.width(1);//k=4
cout << endl;
cout << "i = " << i << endl;
cout << "j = " << j << endl;
cout << "k = " << k << endl;

其对应的输出为

字段默认宽度:0
12345
  abc
aaa
i = 0
j = 3
k = 4

从上面的例子可以看出,将字段宽度设置为3后,字符a显示字符宽度为3,其余位置填充空格,且默认为右对齐。将字段宽度设置为2后,显示字符串"aaa",从结果我们可以看到,字符串正常显示,由此可以看出,cout不会截短数据。当显示完字符串aaa后,我们将字符宽度设置为3,记录上一项目的字符宽度为i,从打印结果来看,当显示完字符串aaa后,宽度自动恢复为默认值0,因此i输出结果为0。

3. 填充字符

默认情况下,cout 使用空格填充字段中未被使用的部分,我们在1.2中的例子已经验证过了,那填充字符可以设置吗?答案是肯定的,使用其成员函数fill()来改变填充字符,例如:

cout.fill('-');
cout << "12345" << endl;
cout.width(2);
cout << 'a' << 'b' << endl;
cout.width(4);
cout << 'a' << 'b' << endl;

输出结果:

12345
-ab
---ab

由输出结果可知,填充字符的设置与字符宽度设置不同的是,新填充的字符将一直有效,直到它更改为止。

4. 设置浮点数的显示精度

C++的默认精度为6位(末尾的0不显示)。coutprecision()成员函数可以设置显示精度,例如:

float a = 3.1415;
float b = 0.123456789;
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout.precision(2);
cout << "a = " << a << endl;
cout << "b = " << b << endl;

输出结果:

a = 3.1415
b = 0.123457
a = 3.1
b = 0.12

从输出结果可以看出,precision()也是设置一次,一直有效,直到重新设置为止。

5. setf()

C++使用setf()成员函数控制小数点被显示时其他几个格式选项,其中cout.setf(std::ios_base::showpoint)设置cout打印浮点类型中末尾的0和小数点。例如:

float a = 13.1415;
float b = 0.123456789;
cout.setf(std::ios_base::showpoint);
cout << "a = " << a << endl;
cout << "b = " << b << endl;
cout.precision(2);
cout << "a = " << a << endl;
cout << "b = " << b << endl;

输出结果:

a = 13.1415
b = 0.123457
a = 13.
b = 0.12

从输出结果可以看出,setf()也是设置一次,一直有效,直到重新设置为止。

setf()有两个原型,第一个为:

fmtflags setf(fmtflags); //fmtflags是bitmask类型(一种用来存储各个位值的类型)的typedef名,用于存储格式的标记

该版本的setf()用来设置单个位控制的格式信息。参数是一个fmtflags值,指出要设置哪一位。返回值的类型为fmtflags的数字,指出所有标记以前的设置。例如要将第11位设置为1,则需要传递一个第11位为1的数字,返回值为原来第11位的值。ios_base类定义了代表位值的常量,下表为其中一部分常用的定义:

常量含义
ios_base::boolalpha输入和输出bool值,可以为truefalse
ios_base::showbase对于输出,使用C++基数前缀(0,0x)
ios_base::showpoint显示末尾的小数点
ios_base::uppercase对于16进制输出,使用大写字母,E表示法
ios_base::showpos在正数前面加上+

:注意,仅当基数为10时才使用加号。C++将十六进制和八进制都视为无符号的,因此对它们,无需使用符号(然而,有些C++实现可能仍然会显示加号)。】

例子:

using std::cout;
using std::endl;
using std::ios_base;
int size = 40;
int a = 63;

cout.width(size);
cout << "cout default: a =  " << a << endl;

cout.width(size);
cout.setf(ios_base::showpos);  //显示+
cout << "cout.setf(ios_base::showpos): a =  " << a << endl;

cout.width(size);
std::hex(cout);  //使用hex
cout << "std::hex(cout): a =  " << a << endl;

cout.width(size);
cout.setf(ios_base::uppercase);  // 使用大写字母
cout << "cout.setf(ios_base::uppercase): a =  " << a << endl;

cout.width(size);
cout.setf(ios_base::showbase);  // 使用0X前缀
cout << "cout.setf(ios_base::showbase): a =  " << a << endl;

cout.width(size);
cout << "cout default: true =  " << true << endl;

cout.width(size);
cout.setf(ios_base::boolalpha);
cout << "cout.setf(ios_base::boolalpha): true =  " << true << endl;

输出结果:

                     cout default: a =  63
     cout.setf(ios_base::showpos): a =  +63
                   std::hex(cout): a =  3f
   cout.setf(ios_base::uppercase): a =  3F
    cout.setf(ios_base::showbase): a =  0X3F
                  cout default: true =  0X1
cout.setf(ios_base::boolalpha): true =  true

第二个setf()原型接受两个参数,并返回以前的设置:

fmtflags setf(fmtflags, fmtflags);

第一参数和以前一样,也是一个包含了所需设置的fmtflags值。第二参数指出要清除第一个参数中的哪些位。例如,将第3位设置为1表示以10为基数,将第4位设置为1表示以8为基数,将第5位设置为1表示以16为基数。假设输出是以10为基数的,而要将它设置为以16为基数,则不仅需要将第5位设置为1,还需要将第3位设置为0——这叫作清除位(clearing the bit)。使用函数setf( )时,要做的工作多些,因为要用第二参数指出要清除哪些位,用第一参数指出要设置哪位。ios_base类为此定义了常量(如下表所示)。

第一个参数第二个参数含义
ios_base::dec ios_base::basefield使用基数10
ios_base::oct ios_base::basefield使用基数8
ios_base::hex ios_base::basefield使用基数16
ios_base::fixed ios_base::floatfield使用定点计数法
ios_base::scientific ios_base::floatfield使用科学计数法
ios_base::leftios_base::adjustfield使用左对齐
ios_base::rightios_base::adjustfield使用右对齐
ios_base ::internal ios_base::adjustfield符号或基数前缀左对齐,值右对齐

具体地说,要修改基数,可以将常量ios_base::basefield用作第二参数,将ios_base::hex用作第一参数。也就是说,下面的函数调用与使用十六进制控制符的作用相同:

cout.setf(ios_base::hex, ios_base::basefield); //与hex(cout);作用相同

其具体使用方法,如下例所示:

cout.setf(ios_base::left, ios_base::adjustfield);//左对齐
cout.setf(ios_base::showpos);//在正数前面加上+
cout.setf(ios_base::showpoint);//显示小数点和末尾的0
cout.precision(3);
//使用科学计数法显示,并保存默认的计数法
ios_base::fmtflags old =
    cout.setf(ios_base::scientific, ios_base::floatfield);
cout << "Left Justification:\n";
long n;
for (n = 1; n <= 41; n += 10) {
    cout.width(4);
    cout << n << "|";
    cout.width(12);
    cout << sqrt(double(n)) << "|\n";
}

cout.setf(ios_base::internal, ios_base::adjustfield);//居中对齐
//恢复默认计数法
cout.setf(old, ios_base::floatfield);
cout << "Internal Justification:\n";
for (n = 1; n <= 41; n += 10) {
    cout.width(4);
    cout << n << "|";
    cout.width(12);
    cout << sqrt(double(n)) << "|\n";
}

cout.setf(ios_base::right, ios_base::adjustfield);//右对齐
cout.setf(ios_base::fixed, ios_base::floatfield);//使用定点计数法
cout << "Right Justification:\n";
for (n = 1; n <= 41; n += 10) {
    cout.width(4);
    cout << n << "|";
    cout.width(12);
    cout << sqrt(double(n)) << "|\n";
}

输出结果:

Left Justification:
+1  |+1.000e+00  |
+11 |+3.317e+00  |
+21 |+4.583e+00  |
+31 |+5.568e+00  |
+41 |+6.403e+00  |
Internal Justification:
+  1|+       1.00|
+ 11|+       3.32|
+ 21|+       4.58|
+ 31|+       5.57|
+ 41|+       6.40|
Right Justification:
  +1|      +1.000|
 +11|      +3.317|
 +21|      +4.583|
 +31|      +5.568|
 +41|      +6.403|

:对于setf()的效果可以通过unsetf()消除,其原型为void unsetf(fmtflags mask);。其中,mask是位模式。mask中所有的位都设置为1,将使得对应的位被复位。也就是说,setf()将位设置为1,unsetf()将位恢复为0。】

6. 标准控制符

对于用户来说,使用setf()进行格式化并不是最友好的方法。为此C++提供了多个控制符来完成相应的格式化效果,其能够调用setf(),并自动提供正确的参数。例如我们前面介绍过的dechexoct。C++常用控制符如下表所示:

控制符调用
boolalphasetf(ios_base::boolalpha)
noboolalphaunset(ios_base::noboolalpha)
showbasesetf(ios_base::showbase)
noshowbaseunsetf(ios_base::showbase)
showpointsetf(ios_base::showpoint)
noshowpoint unsetf(ios_base::showpoint)
showpos setf(ios_base::showpos)
noshowposunsetf(ios_base::showpos)
uppercasesetf(ios_base::uppercase)
nouppercaseunsetf(ios_base::uppercase)
internalsetf(ios_base::internal, ios_base::adjustfield)
leftsetf(ios_base::left, ios_base::adjustfield)
rightsetf(ios_base::right, ios_base::adjustfield)
decsetf(ios_base::dec, ios_base::basefield)
hexsetf(ios_base::hex, ios_base::basefield)
octsetf(ios_base::oct, ios_base::basefield)
fixedsetf(ios_base::fixed, ios_base::floatfield)
scientificsetf(ios_base::scientific, ios_base::floatfield)
7. 头文件iomanip

使用iostream工具来设置一些格式值(如字段宽度)非常麻烦。为了简化工作,C++在头文件中提供了其他的一些控制符,不但可以提供前面提到过的格式设置,而且用起来方便。其中常用的控制符如下:

 setprecision()//设置精度,其接受一个指定精度的整数参数
 setfill()     //填充字符,其接受一个指定填充字符的char参数
 setw()        //设置字段宽度,其接受一个指定字段宽度的整数参数。

由于它们都是控制符,因此可以用cout语句连接起来。这样,setw()控制符在显示多列值时尤其方便。其使用方法如下例所示:

#include <cmath>
#include <iomanip>
#include <iostream>
int main() {
    using namespace std;
    // use new standard manipulators
    cout << fixed << right;
    // use iomanip manipulators
    cout << setw(6) << "N" << setw(14) << "square root" << setw(15)
        << "fourth root\n";
    double root;
    for (int n = 10; n <= 100; n += 10) {
        root = sqrt(double(n));
        cout << setw(6) << setfill('.') << n << setfill(' ') << setw(12)
            << setprecision(3) << root << setw(14) << setprecision(4) << sqrt(root)
            << endl;
    }
    return 0;
}

输出结果:

     N   square root   fourth root
....10       3.162        1.7783
....20       4.472        2.1147
....30       5.477        2.3403
....40       6.325        2.5149
....50       7.071        2.6591
....60       7.746        2.7832
....70       8.367        2.8925
....80       8.944        2.9907
....90       9.487        3.0801
...100      10.000        3.1623

:最后一行10.000,是使用fixed控制符导致显示末尾的0。】

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

艰默

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值