zoukankan      html  css  js  c++  java
  • C++_IO与文件2-用cout进行输出

    C++将输出流看作是字节流,在程序中,很多数据被组织成比字节更大的单位。

    例如int类型由16位或者32位的二进制值表示;double值由64位的二进制数据表示;

    但是在将字节流发送给屏幕时,希望每个字节表示一个字符。

    举个例子:要在屏幕上显示数字-2.34时,需要5个字符(- 2 . 3 4)。

    而不是这个值得内部浮点表示发送到屏幕上。

    ostream类最重要的任务就是将数值类型转换为以文本形式表示的字符流

    ostream类将数据的内部表示(二进制位模式)转换为由字符字节组成的输出流。

    //输出流是字节流,所以要显示的东西必须进行转换,转换成字符编码的字节流;

    =====================================================

    一、重载的<<运算符

    ostream类重新定义了<<运算符,方法是将其重载为输出。该重载运算符能够识别C++中所有的基本类型;

    <<运算符的默认含义是按位左移运算符。

    例如:cout<<88对应于下面的方法原型:

    ostream & operator<<(int);

    operator<<(int)函数接受一个int参数,返回一个指向ostream对象的引用,这使得可以将输出连接起来,如下所示:

    cout<<"I'm feeling sedimental over "<<boundary<<" ";

    1、输出和指针

    ostream类为下面的指针类型提供了插入运算符函数:

    const signed char *

    const unsigned char *

    const char *

    void *

    C++用指向字符串存储位置的指针来表示字符串。指针的形式可以是char数组名、显式的char指针或用引号括起的字符串。

    方法使用字符串中的终止空字符来确定何时停止显示字符。

    void * 指的是其他类型的指针,会打印地址的数值表示;如果要获得字符串的地址,则必须将其强制转换为其他类型:

    char * amount = "dozen";

    cout<<amount;              //print the string "dozen"

    cout<<(void *)amount;   //prints the address of the "dozen" string

     

    2、拼接输出

    插入运算符的所有返回为ostream &,也就是说,原型的格式如下:

    ostream & operator<<(type);

    type是要显示的数据类型,ostream &意味着将返回一个指向ostream对象的引用。

    指向哪个对象呢?函数定义指出,引用将指向用于调用该运算符的对象。

    换句话说,运算符函数的返回值为调用运算符的对象。

    例如:cout<<"potluck"返回的是cout对象。这种特性使得能够通过插入运算符来连接输出。 

    =====================================================

    二、其他ostream方法

    ostream类还提供了put()方法和write()方法;前者显示字符、后者用于显示字符串

    可以用类方法表示法来调用put:

    cout.put('W');   //display the W character

    cout是调用对象的方法、put是类成员函数。该函数也返回一个指向调用对象的引用,因此可以用它拼接输出;

    write()方法显示整个字符串,其模板原型如下:

    basic_ostream<char T, traits> & write(const char_type* s, streamsize n);

    接下来看一个例子:

     1 //write.cpp  -- using cout.write()
     2 #include <iostream>
     3 #include <cstring>
     4 
     5 int main()
     6 {
     7     using std::cout;
     8     using std::endl;
     9     const char * state1 = "Florida";
    10     const char * state2 = "Kansas";
    11     const char * state3 = "Euphoria";
    12 
    13     int len = std:strlen(state2);
    14     cout<<"Increasing loop index:
    ";
    15     int i;
    16     for (i = 1; i<=len; i++)
    17     {
    18         cout.write(state2, i);
    19         cout<<endl;
    20     }
    21 
    22 //concatenate output
    23     cout<<"Decreasing loop index:
    ";
    24     for(i = len; i>0; i--)
    25         cout.write(state2, i) <<endl;
    26 
    27 //exceed string length
    28     cout<<"Exceeding string length:
    ";
    29     cout.write(state2, len+5)<<endl;
    30 
    31     return 0;
    32 }

    程序输出结果

    Increasing loop index:

    K

    Ka

    Kan

    Kans

    Kansa

    Kansas

    Decreasing loop index:

    Kansas

    Kansa

    Kans

    Kan

    Ka

    K

    另外,write()方法也可以用于数值数据,可以将数字的地址强制转换为char *,然后传递给它:

    long val = 560031841;

    cout.write((char *) & val, sizeof(long)); 

    这不会将数字转换为相应的字符,而是传输内存中存储的位表示。

    例如,4字节的long值(560031841)将作为4个独立的字节被传输。输出设备将把每个字节作为ASCII码进行解释。

    因此在屏幕上,560031841将被显示为4个字符的组合,这很可能是乱码。

    write()确实为将数值数据存储在文件中提供了一种简洁、准确的方式。

    =====================================================

    三、刷新输出缓冲区

    缓冲区一般为512个字节或者其整数倍。

    输出不会立即发送到目标地址,而是被存储在缓冲区中,直到缓冲区填满。

    然后程序将刷新(flush)缓冲区,把内容发送出去,并清空缓冲区,以填充新的数据。

    但是对于屏幕输出而言,填充缓冲区的重要性低很多。

    所幸,在屏幕输出时,程序不必等到缓冲区被填满后才刷新缓冲区;

    当换行符发送到缓冲区后,将刷新缓冲区。

    cout<<"Hello, good-looking! "<<flush;

    cout<<"Wait just a moment, please"<<endl;

    控制符flush刷新缓冲区,而控制符endl也刷新缓冲区;

    cout<<"Enter a number:";

    float num;

    cin>>num;

    上面这段代码,没有刷新缓冲区,从而显示Enter a number: 字符,那样的话用户也就无法从屏幕感知到这个提示语来进行输入;

    =====================================================

    四、用cout进行格式化

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

    可以使用:hex(cout) 表示下面的函数调用将cout对象的计数系统格式状态设置为十六进制。 

    但通常的使用方法为:cout<<hex;

     1 //manip.cpp  --  using format manipulators
     2 #include <iostream>
     3 
     4 int main()
     5 {
     6     using namespace std;
     7     cout<<"Enter an integer: ";
     8     int n;
     9     cin>> n;
    10 
    11     cout<<"n      n*n
    ";
    12 
    13 //set to hex mode
    14     cout<<hex;
    15     cout<<n << "   ";
    16     cout<<n*n<<" (hexdecimal)
    ";
    17 
    18 //set to octal mode
    19     cout<<oct<<n<<"   "<<n*n<<" (octal)
    ";
    20 
    21 //alternative way to call a manipulator
    22     dec(cout);
    23     cout<<n<<"     "<<n*n<<" (decimal)
    ";
    24 
    25     return 0; 
    26 }

    运行结果为:

    Enter an integer:13

    n       n*n

    13     169(decimal)

    d        a9 (hexadecimal)

    15     251(octal)

    13     169(decimal)

    2、调整字段宽度

      先看一个例子:

        cout<<'#';

        cout.width(12);

        cout<<12<<"#"<<  24<<"# ";

      显示结果:

        #          12#24#

    我们可以发现第一个12被设置为宽度12的字段,12这个字符被放到最右边,这被称为右对齐。

    然后字段宽度恢复为默认值。

    所以可知width()方法只影响接下来显示的一个项目,然后字段宽度将恢复为默认值。

    另外注意一点,C++永远不会截短数据,因此如果试图在宽度为2的字段中打印一个7位值,C++将增宽字段,以容纳该数据。

    C/C++的原则是显示所有数据比保持列的整洁更重要。

     1 //width.cpp   -- using the width method 
     2 #include <iostream>
     3 
     4 int main()
     5 {
     6     using std :: cout;
     7     int w = cout.width(30);
     8     cout<<"default field width =" << w <<" : 
    ";
     9     cout.width(5);
    10     cout<<"N"<<' : ';
    11     cout.width(8);
    12     cout<<"N*N"<<":
    ";
    13  
    14     for (long i = 1; i<=100; i*=10)
    15     {
    16         cout.width(5);
    17         cout<<i<<' : ';
    18         cout.width(8);
    19         cout<<i * i<<":
    ";
    20     } 
    21 
    22     return 0;
    23 }

    运行结果:

               default field width = 0;

        N:     N * N:

        1:           1:

      10:       100:

    100:   10000:

    空格被插入到值的左侧,用来填充的字符叫做填充字符右对齐是默认的

    默认字段宽度是0,因为C++总会增长字段,以容纳数据,因此这种值适用于所有数据。

    3、填充字符

    在默认情况下,cout用空格填充字段中未被使用的部分,可以用fill()成员函数来改变填充字符。

    下面的函数调用将填充字符改为星号:

    cout.fill(' * '); 

    注意,与字段宽度不同的是,新的填充字符将一直有效,直到更改它为止;

     1 //fill.cpp  -- changing fill character for fields
     2 #include<iostream>  
     3 
     4 int main()
     5 {
     6     using std::cout;
     7     cout.fill('*');
     8     const char * staff[2] = {"Waldo Whipsnade", "Wilmarie Wooper"};
     9     long bonus[2] = {900, 1350};
    10     
    11     for (int i = 0; i < 2; i++)
    12     {
    13         cout<<staff[i]<<" : $";
    14         cout.width(7);
    15         cout<<bonus[i]<<"
    ";
    16     }
    17     return 0;
    18 }

    运行结果:

    Waldo Whipsnade: $****900
    Wilmarie Wooper: $***1350

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

    浮点数精度的含义取决于输出模式;

    在默认模式下,它指的是显示的总位数

    在定点模式和科学模式下,精度指的是小数点后面的位数

    C++的默认精度为6位(但末尾的0将不显示)。 

    precision()成员函数使得能够选择其他值。

    下面的语句将cout的精度设置为2:cout.precision(2)

    与fill()类似,新的精度设置将一直有效,直到被重新设置。

     1 //precise.cpp  -- setting the precision
     2 #include<iostream>  
     3 
     4 int main()
     5 {
     6     using std::cout;
     7     float price1 = 20.40;
     8     float price2 = 1.9 + 8.0/9.0;
     9     
    10     cout<<""Fiery Friends" is $"<<price1<<"!
    ";
    11     cout<<""Fiery Friends" is $"<<price2<<"!
    ";
    12     
    13     cout.precision(2)
    14     cout<<""Fiery Friends" is $"<<price1<<"!
    ";
    15     cout<<""Fiery Friends" is $"<<price2<<"!
    ";
    16     
    17     return 0;
    18 }

    运行结果:

    "Furry Friends" is 20.4!
    "Furry Friends" is 2.78889!
    "Furry Friends" is 20!
    "Furry Friends" is 2.8!

    5、打印末尾的0和小数点

    对于有些输出,保留末尾的0将更为美观。

    但ios_base类提供了一个setf()函数(用于set标记),能够控制多种格式化特性。

    这个类还定义了很多常量,可用作该函数的参数;

    例如,下面的函数调用使cout显示末尾小数点:

    cout.setf(ios_base :: showpoint);

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

    如果使用默认精度(6位)时,cout不会将2.00显示为2,而是将它显示为2.000000。

     1 //precise.cpp  -- setting the precision
     2 #include<iostream>  
     3 
     4 int main()
     5 {
     6     using std::cout;
     7     using std::ios_base;
     8     
     9     float price1 = 20.40;
    10     float price2 = 1.9 + 8.0/9.0;
    11     
    12     cout.setf(ios_base::showpoints);
    13     cout<<""Fiery Friends" is $"<<price1<<"!
    ";
    14     cout<<""Fiery Friends" is $"<<price2<<"!
    ";
    15     
    16     cout.precision(2)
    17     cout<<""Fiery Friends" is $"<<price1<<"!
    ";
    18     cout<<""Fiery Friends" is $"<<price2<<"!
    ";
    19     
    20     return 0;
    21 }

    运行结果:

    "Fiery Friends" is $20.4000!
    "Fiery Friends" is $2.78889!
    "Fiery Friends" is $20.!
    "Fiery Friends" is $2.8!

    6、再谈setf()

    ios_base类定义了代表位值的常量;//由于这些格式常量都在ios_base类中定义。因此使用它们时,必须加上作用域解析运算符;

    ios_base : : boolalpha   输入和输出bool值,可以为true或false

    ios_base : : showbase  对于输出,使用C++基数前缀(0, 0x)

    ios_base : : showpoint  显示末尾的小数点

    ios_base : : uppercase  对于16进制输出,使用大写字母,E表示法

    ios_base : : showpos   在整数前面加上+

    setf()函数由两个原型第一个为:

    fmtflags setf(fmtflags);

    fmtflags 是bitmask类型的typedef名,用于存储格式标记。

    bitmask类型是用来存储各个位值的类型。

     1 //setf.cpp  -- using setf() to control formatting
     2 #include<iostream>  
     3 
     4 int main()
     5 {
     6     using std::cout;
     7     using std::endl;
     8     using std::ios_base;
     9     
    10     int temperature = 63;
    11     cout<<"Today's water temperature: ";
    12     cout.setf(ios_base :: showpos);  //show plus signal
    13     cout<< temperature << endl;
    14 
    15     cout<<"For our programming friends, that's
    ";
    16     cout<< std::hex << temperature << endl;  //use hex
    17     cout.setf(ios_base::uppercase);  //use uppercase in hex
    18     cout.setf(ios_base::showbase);  //use 0X prefix for hex
    19     cout<<"or
    ";
    20     cout<<temperature<<endl;
    21     cout<<"How "<<true<<"!   oops  -- How ";
    22     cout.setf(ios_base::boolappha);
    23     cout<<true<<<<"!
    ";
    24     
    25     return 0;
    26 }

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

    fmtflags setf(fmtflags, fmtflags);

    函数的这种重载格式用于设置由多位控制的格式选项。

    第一个参数和以前一样,也是一个包含了所需设置的fmtflags值。

    第二个参数指出要清除第一个参数中的哪些位。

          setf(long, long)的参数

      第二个参数                 第一个参数           含义

    ios_base::basefield     ios_base::dec      使用基数10

                                       ios_base::oct       使用基数8

                                       ios_base::hex      使用基数16

    ios_base::floatfield     ios_base::fixed     使用定点计数法

                                      ios_base::scientific 使用科学计数法

    ios_base::adjustfield  ios_base::left        使用左对齐

                                      ios_base::right      使用右对齐

                                      ios_base::internal   符号或基数前缀

    7、标准控制符

    使用setf()不是进行格式化的,对用户最友好的方法;

    C++提供了多个控制符,能够调用setf(),并自动提供正确的参数;

          一些标准控制符

       控制符        调用

         boolalpha                    setf(ios_base::boolalpha)

      noboolalpha               unsetf(ios_base::noboolalpha)

        showbase                   setf(ios_base::showbase)

       noshowbase               unsetf(ios_base::showbase)

         等等。。。

     

    8、头文件iomanip

    使用iomanip工具来设置一些格式值不太方便。

    为了简化工作,C++在头文件iomanip中提供了其他一些控制符,它们能够提供前面讨论过的服务,但表示起来更方便。

    3个最常用的控制符分别是:setprecision()、setfill()、setw();

    它们分别用来设置精度、填充字符、字段宽度;

     1 //iomanio.cpp  -- using manipulators from iomanip
     2 #include<iostream>  
     3 #include<iomanip>
     4 #include<cmath>
     5 
     6 int main()
     7 {
     8     using namespace std;
     9     cout<<fixed<<right;
    10     
    11     cout<<setw(6)<<"N"<<setw(14)<<"square root"<<setw(15)<<"fourth root
    ";
    12     
    13     double root;
    14     for(int n =10; n<=100; n+=10)
    15     {
    16         root = sqrt(double(n));
    17         cout<<setw(6)<<setfill('.')<<n<<setfill(' ')
    18             <<setw(12)<<setprecision(3)<<root
    19             <<setw(14)<<setprecision(4)<<sqrt(root)
    20             <<endl;
    21     }
    22     
    23     return 0;
    24 }
  • 相关阅读:
    Oracle备份恢复之无备份情况下恢复undo表空间
    Oracle HA 之 测试RAC的功能
    (转)Python——functools
    (转)Python标准库:内置函数print(*objects, sep=' ', end=' ', file=sys.stdout, flush=False)
    (转)用Python写堡垒机项目
    (转)Python进阶:函数式编程(高阶函数,map,reduce,filter,sorted,返回函数,匿名函数,偏函数)
    (转)Linux中的位图
    (转)Python标准库02 时间与日期 (time, datetime包)
    (转)Python 3 collections.defaultdict() 与 dict的使用和区别
    (转)python高级:列表解析和生成表达式
  • 原文地址:https://www.cnblogs.com/grooovvve/p/10493555.html
Copyright © 2011-2022 走看看