使用cout进行格式化

以下内容摘自木缥缈的博客


使用cout进行格式化

  ostream插入运算符将值转换为文本格式。在默认情况下,格式化值的方式如下。

    *  对于char值,如果它代表的是可打印字符,则将被作为一个字符显示在宽度为一个字符的字段中。

    *  对于数值整型,将以十进制方式显示在一个刚好容纳该数字及负号(如果有的话)的字段中;

    *  字符串被显示在宽度等于该字符串长度的字段中。

  浮点数的默认行为有变化。下面详细说明了老式实现和新式实现之间的区别。

    *新式:浮点类型被显示为6位,末尾的0不显示(注意,显示的数字位数与数字被存储时精度设置没有任何关系)。数字以定点表示法显示还是科学计数法表示,取决于它的值。具体来说,当指数大于等于6或小于等于-5时,将使用科学计数法表示。另外,字段宽度恰好容纳数字和负号(如果有的话)。默认的行为对应于带%g说明符的标准C库函数fprintf()。

    *老式:浮点类型显示为带6位小数,末尾的0不显示(注意,显示的数字位数与数字被存储时的精度没有任何关系)。数字以定点表示法显示还是以科学计数法表示,取决于他的值。另外,字段宽度恰好容纳数字和负号(如果有的话)。

  因为每个值的显示宽度等于它的长度,因此必须显式地在值之间提供空格;否则,相邻的值将不会被分开。

  注意:并非所有的编译器都能生成符合当前C++标准格式的输出。另外,当前标准允许区域性变化。例如,欧洲实现可能遵循欧洲人的风格:使用逗号而不是句点来表示小数点。也就是说,2.54将被写成2,54 。区域库(头文件locale)提供了用特定的风格影响(imbuing)输入或输出流的机制,所以同一个编译器能够提供多个区域选项。本章使用美式格式。  

(1)修改显示时使用的计数系统

  ostream类是从ios类派生来的,而后者是从ios_base派生来的。ios_base类存储了描述格式状态的信息。例如,一个类成员中某些位决定了使用的计数系统,而另一个成员则决定了字段宽度。通过使用控制符(manipulator),可以控制显示整数时使用的技术系统。通过使用ios_base的成员函数,可以控制字段宽度和小数位数。由于ios_base类是ostream的间接基类,因此可以将其方法用于ostream对象(或子代),如cout。

  注意:ios_base类中的成员和方法以前位于ios中。现在,ios_base是ios的基类。在新系统中,ios是包含char和wchar_t具体化的模板,而ios_base包含了非模板特性。

  要控制整数以十进制、十六进制还是八进制显示,可以使用dec、hex和oct控制符。例如,下面的函数调用将cout对象的计数系统格式状态设置为十六进制:

    hex(cout);

    完成上述设置后,程序将以十六进制形式打印整数值,直到将格式状态设置为其他选项为止。注意,控制符不是成员函数,因此不必通过对象来调用。

  虽然控制符实际上是函数,但它们通常的使用方式为:

    cout << hex;

    ostream类重载了<<运算符,这使得上述用法与函数调用hex(cout)等价。控制符位于名称空间std中。下面的代码演示了控制符的使用方法(注意,可以单独使用控制符,也可以将其作为一系列插入的部分):

#include <iostream>

int main()
{ using namespace std;
    cout << "输入一个数字:"; int n;
    cin >> n;
    std::string str(5,' ');
    cout << "n" << str << "n*n\n";
    cout << n << str << n*n << "(decimal)\n"; //设置成十六进制系统
    cout << hex;
    cout << n << str;
    cout << n*n << " (hexadecimal)\n"; //设置为八进制系统
    cout << oct << n << str << n * n << " (octal)\n";

    dec(cout);
    cout << n << str << n * n << " (decimal)\n"; return 0;
}

输出结果:
输入一个数字:12 
n     n*n 
12     144 (decimal)
c     90 (hexadecimal) 
14     220 (octal) 
12     144  (decimal)

(2)调整字段宽度

  可以使用width成员函数将长度不同的数字放到宽度相同的字段中,该方法的原型为:

    int width();

    int width(int i);

  第一种格式返回字段宽度的当前设置;第二种格式将字段宽度设置为i个空格,并返回以前的字段宽度值。这使得能够保存以前的值,以便以后恢复宽度值时使用。

  width()方法之影响显示的下一个项目,然后字段宽度将恢复为默认值。由于width()是成员函数,因此必须使用对象来调用它。

  C++永远不会截短数据,因此如果试图在宽度为2的字段中打印一个7位值,C++将增宽字段,以容纳该数据。C/C++的原则是:显示所有的数据比保持列的整洁更重要;C++视内容重于形式。

 1 #include <iostream>
 2 
 3 int main() 4 {
 5     using namespace std; 6     size_t w = cout.width(30);
 7     cout << "Default field width = " << w << ":\n";
 8     cout.width(5);
 9     cout << "N" << ':'; 
10     cout.width(8); 
11     cout << "N * N" << ":\n"; 
12     
13     for (long i = 1; i <= 100; i *= 10) { 
14         cout.width(5); 
15         cout << i << ':'; 
16         cout.width(8);
17         cout << i * i << ":\n"; 
18 } 
19     return 0; 
20 }
21 
22 输出结果: 
23         Default field width = 0: 
24     N:   N * N:
25     1:       1: 
26    10:     100: 
27   100:   10000:

  在上面的输出中,值在字段中右对齐。输出中包含空格,也就是说,cout通过加入空格来填满整个字段。右对齐时,空格被插入到值的左侧。用来填充的字符叫做填充字符(fill character)。右对齐是默认的。

(3)填充字符

  在默认情况下,cout使用空格填充字段中未被使用的部分,可以使用fill()成员函数来改变填充字符。例如,下面的函数调用将填充字符改为星号:
    cout.fill('*');

  这对于检查打印结果,防止接收方添加数字很有用。

#include <iostream>

int main()
{
    using namespace std;
    cout.fill('*');
    const char * staff[2] = {"iPhone6s", "iPad2"};
    long bonus[2] = {900,1350};
    for (int i = 0; i < 2; i ++) {
        cout.width(10);
        cout << staff[i] << ": $";
        cout.width(7);
        cout << bonus[i] << "\n";
    }
    return 0;
}

输出结果:
**iPhone6s: $****900
*****iPad2: $***1350

(4)设置浮点数的显示精度

  浮点数精度的含义取决于输出模式。在默认情况下,它指的是显示的总位数。在定点模式和科学模式下,精度指的是小数点后面的位数。已经知道,C++的默认精度为6位(但末尾的0将不显示)。precision成员函数使得能够选择其他值。例如,下面的函数调用将cout的精度设置为2:

    cout.precision(2);

  和width()的情况不同,但与fill()相似,新的精度设置将一直有效,直到被重新设置。下面的程序说明了这一点:

#include <iostream>

int main()
{
    using namespace std;
    float price1 = 25.5;
    float price2 = 1.9 + 8.0/9.0;
    cout.width(10);
    cout << "\"Apple\"" << ": $" << price1 << "\n";
    cout.width(10);
    cout << "\"Flower\"" << ": $" << price2 << "\n";
    
    cout.precision(2);
    cout.width(10);
    cout << "\"Apple\"" << ": $" << price1 << "\n";
    cout.width(10);
    cout << "\"Flower\"" << ": $" << price2 << "\n";
    
    return 0;
}

输出结果:
   "Apple": $25.5
  "Flower": $2.78889
   "Apple": $26
  "Flower": $2.8

注意,第3行没有打印小数点及其后面的内容。另外,第4行显示的总位数为2位。

(5)打印末尾的0和小数点

  对于有些输出,希望保留末尾的0,iostream系列类没有提供专门用于完成这项任务的函数,但ios_base类提供了一个setf()函数(用于set标记),能够控制多种格式化特性。这个类还定义了多个常量,可以作为函数的参数。例如,下面的函数调用使cout显示末尾的小数点:

    cout.setf(ios_base::showpoint);

  使用默认的浮点格式时,上述语句还将导致末尾的0被显示出来。

  showpoint是ios_base类声明中定义的类级静态常量。类级意味着如果在成员函数定义的外面使用它,则必须在常量名前加上作用域运算符(::)。因此,ios_base::showpoint指的是在ios_base类中定义的一个常量。

#include <iostream>

int main()
{
    using namespace std;
    float price1 = 25.5;
    float price2 = 1.9 + 8.0/9.0;
    cout.setf(ios_base::showpoint);
    cout.width(10);
    cout << "\"Apple\"" << ": $" << price1 << "\n";
    cout.width(10);
    cout << "\"Flower\"" << ": $" << price2 << "\n";
    
    cout.precision(2);
    
    cout.width(10);
    cout << "\"Apple\"" << ": $" << price1 << "\n";
    cout.width(10);
    cout << "\"Flower\"" << ": $" << price2 << "\n";
    
    return 0;
}

输出结果:
   "Apple": $25.5000
  "Flower": $2.78889
   "Apple": $26.
  "Flower": $2.8
posted @ 2018-02-22 22:06  Elis  阅读(623)  评论(0编辑  收藏  举报