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设置格式一般按如下方式进行:

 

1
2
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>,因此默认包含的头文件均为:

1
2
#include <iomanip>
#include <iostream>

 

二、缩进

将输出内容按指定的宽度对齐,需要用到ios::right、ios::left、ios::internal和iomanip里的setw。其中setw用于指定要输出内容的对齐宽度。以下两段代码的结果完全相同,前面是一个浮点数-456.98,后面紧跟着一个字符串“The End”以及换行符“endl”。

 

代码一:

1
2
3
4
5
6
7
8
9
10
11
12
#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;
}

 

代码二:

1
2
3
4
5
6
7
8
9
#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”作为填充字符:

1
2
3
4
5
6
7
#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使所有字母以大写表示。代码示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#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来为整数的前面加一个表示进制的前缀,代码如下:

1
2
3
4
5
6
7
8
#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来代替,其结果是完全相同的:

1
2
3
4
5
6
7
8
9
10
#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配合使用,可以表示指定小数点后面的保留位数(四舍五入)。示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#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

 

需要注意的是,有时会因为机器的精度问题导致四舍五入的结果不正确。这种问题一般需要手动修正,见如下代码示例:

1
2
3
4
5
6
7
8
#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不会读入默认或指定的结束字符,但在调用之后读取的位置已经跳过结束字符。调用示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
#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可以禁止或启用缓冲区。示例代码如下:

1
2
3
4
5
6
7
8
#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

 

六、综合使用

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#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


  • 27
    点赞
  • 143
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 下面是用 Qt 和 C++ 输出圣诞树的一种方法: ```cpp #include <QApplication> #include <QTextStream> int main(int argc, char *argv[]) { QApplication app(argc, argv); QTextStream cout(stdout); int n = 5; // 圣诞树的高度,可以根据需要自行调整 for (int i = 0; i < n; i++) { for (int j = 0; j < n - i - 1; j++) cout << " "; // 输出空格 for (int j = 0; j < 2 * i + 1; j++) cout << "*"; // 输出星号 cout << endl; // 换行 } return 0; } ``` 运行程序后,将会在终端中输出一个高度为 5 的圣诞树。 圣诞树的形状是由一个个星号组成的,星号的数量和圣诞树的高度有关,具体计算方法是:每层输出的星号数量为 2 × 层数 + 1。例如,第一层的星号数量为 2 × 0 + 1 = 1,第二层的星号数量为 2 × 1 + 1 = 3。 圣诞树的形状需要保持对称,所以需要在每层输出星号之前先输出一些空格来确保圣诞树看起来整齐。空格的数量也是有规律的,每层输出的空格数量为圣诞树的高度减去当前层数再减 1。例如,圣诞树的高度为 5,第一层输出的空格数量为 5 - 0 - 1 = 4,第二层输出的空格数量为 5 - 1 - 1 = 3。 程序中的 ### 回答2: 使用Qt和C语言输出一个圣诞树可以通过绘制图形来实现。首先,需要在Qt中创建一个窗口并定义画布大小和背景颜色。然后,通过在画布上绘制三角形和矩形来实现圣诞树的形状。 首先,我们可以定义三角形的坐标和颜色,可以使用Qt的QPolygon类来表示三角形的坐标,然后使用QPainter类将三角形绘制在画布上。 接下来,我们可以定义矩形的坐标和颜色,可以使用Qt的QRect类来表示矩形的位置和大小,然后再次使用QPainter类将矩形绘制在画布上,作为圣诞树的主干。 最后,我们可以通过添加圆形来代表圣诞树装饰品,可以使用Qt的QPainter类的drawEllipse方法绘制圆形,并且可以设置不同的颜色和位置。 绘制完成后,再通过Qt的QWidget类将画布显示在窗口上,以便可以看到圣诞树的效果。 总结来说,使用Qt和C语言输出一个圣诞树需要创建窗口、定义画布大小、绘制三角形、矩形和圆形,并通过QWidget类将画布显示在窗口上。这样就可以实现一个简单的圣诞树的输出。 ### 回答3: 使用Qt和C语言绘制一个圣诞树的过程如下: 1. 首先在Qt界面上创建一个窗口,设置窗口的大小和背景色。 2. 使用Qt提供的绘图函数,在窗口上绘制一个绿色的三角形作为圣诞树的身体。可以使用QPainter类的drawPolygon函数来实现,设置三角形的三个顶点坐标即可。 3. 继续使用绘图函数,在圣诞树的身体上绘制装饰品或花纹。可以使用QPainter类的drawEllipse函数来绘制圆形装饰物,设置圆心坐标和半径即可。可以绘制各种颜色和大小的装饰品,如红色的圆圈、黄色的五角星等。 4. 在圣诞树的底部绘制一个矩形作为树干。使用QPainter类的drawRect函数来实现,设置矩形的左上角和右下角坐标即可。 5. 最后,使用Qt提供的文字绘制函数,在圣诞树上方绘制一段文字,例如“Merry Christmas”来为圣诞树添加祝福语。可以使用QPainter类的drawText函数来实现,设置文本的位置和字体样式即可。 通过上述步骤,就可以使用Qt和C语言绘制一个简单的圣诞树了。可以根据需要添加更多的细节,如树枝、礼物盒等,以使圣诞树更加丰富和生动。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值