开源时代C++

c++ 输入输出流 缓冲区 概述

2017-04-28  本文已影响235人  Tianql

c++的输入输出不是建立在语言上的,而是由iostreamfstream文件中定义的一组模板类实现的,且这个类库不是正式语言定义的组成部分,就是说cin,cout等并不是语言的关键字.

流和缓冲区

c++把输入输出看作是字节流,输入时,程序从输入流中截取(>>)字符,输出时,程序将字节插入(<<)到输出流.通过这样的方式,流就相当于连接输入端和输出端的一个桥梁,两端只需要关联到相应的流上即可实现连接,这样处理输入输出的方式将独立与流的去向.
如下图所示:

缓冲区是指用作中介的内存块,主要作用是用来提高处理输入输出的效率.原因在于像磁盘驱动器这样的设备通常是以512字节的块为单位来传输信息,而程序每次只能处理一个字节.所以通过缓冲的方法,一次从磁盘读取大量的信息存储到缓冲区,程序再从缓冲区中每次读取一个字节,因为从内存中读取一个字节的时间要远小于从磁盘读取的时间.

c++I/O文件

各个I/O类的继承关系如下图所示:

  • ios_basic类表示流的一般特性,如是否可读取,是二进制流还是文本流.以及独立于类型的一些特性.

在程序中包含iostream文件将自动创建8个流对象,4个窄字符流,4个宽字符流:

  • cin默认关联标准输入设备,wcin与此类似,用于处理wchar_t类型

如上所知,c++的以上几个对象就代表了c++的输入输出流.所以在流对象中就包含了与输入输出有关信息的数据成员,如显示数据时使用的字段宽度,小数位数等...

重定向

由上面流的概述可知流只是充当连接输入端和输出端的一个桥梁而已.所以我们就可以通过改变流的流向来实现输入输出的重定向功能.

  • 标准输入重定向 <

假设我们有一个程序counter从键盘接受输入字符,并返回输入字符的个数.那么我们只需如下就可以让counter从文件input.txt中输入字符,并把结果存到res.txt中:

counter <input.txt >res.txt

cout进行输出

ios_basic类中存储了描述格式状态的信息,如计数系统,字段宽度,小数位数等,并提供了控制符来控制显示整数时的计数系统,由于ios_basic类是ostream类的间接基类,所以可在ostream类的对象中直接使用.例如,要控制整数以十进制,十六进制,八进制显示可分别使用dec,hex,oct控制符.
hex(cout); // 控制符不是成员函数,不必通过对象调用
进行如上设置后,cout将以十六进制显示,直到将格式设置为其他选项为止.因为ostream重载了<<,所以一般以cout<<hex;方式单独使用控制符.
ps: 对于cin,以上控制符也是可用的,表示以什么进制解释输入的整数

字段宽度

使用成员函数width()可实现将长度不同的数字放到宽度相同的字段中.原型为:

int width();      // 返回字段宽度的当前设置
int width(int i); // 将字段宽度设置为i并返回设置之前的字段宽度

注意: width()函数只影响接下来的一个项目,之后字段将恢复到默认值

填充字符

默认的cout使用空格填充字段中未被使用的部分,可使用成员函数fill(char)可改变填充字符.与字段宽度设置不同的是它会一直有效直到更改为止.

设置浮点数显示精度

已知c++默认精度是6位,但末尾的0不显示.可以使用成员函数precision(int)来设置显示的精度,也就是数据的总位数.与fill()类似,一旦设置就一直有效直到被更改.
有时输出需要显示末尾的0和小数点,ostream类本身没有提供这方面的函数,它的基类ios_basic类提供的成员函数setf()可以实现控制多种格式化特性,
使用setf()函数需要进行很多设置,用到很多的ios_basic的类级静态常量,不是很友好.c++在头文件iomanip中提供了其他一些控制符可以更方面的实现格式化特性.如下给出三个最常用的控制符:

  • setpricision(int): 设置精度

举例如下:

#include<cmath>
#include<iomanip>
#include<iostream>

int main()
{
    std::cout << std::fixed << std::right; // 显示m末尾的0; 右对齐
    std::cout << std::setprecision(4);     // 设置显示精度,一直有效

    std::cout << std::setw(6) << "N" << std::setw(15) << "squre root" << std::setw(15) << "fourth root" << std::endl;
    for (int i=10; i<=100; i+=10)
    {
                    // 设置字段宽度(只对下一条输出内容有效)和填充字符(一直有效)
        std::cout   << std::setw(4) << std::setfill('.') << i 
                    << std::setw(15) << std::setfill(' ') << sqrt(i) << std::setw(15) << sqrt(sqrt(i)) << std::endl;
    }
    return 0;
}

//下面为输出
   N     squre root    fourth root
..10         3.1623         1.7783
..20         4.4721         2.1147
..30         5.4772         2.3403
..40         6.3246         2.5149
..50         7.0711         2.6591
..60         7.7460         2.7832
..70         8.3666         2.8925
..80         8.9443         2.9907
..90         9.4868         3.0801
.100        10.0000         3.1623

cin进行输入

cin可自动识别输入的数据类型,也就是说,它读取从非空白符开始到与目标类型不匹配的第一个字符之间的所有内容.剩下不匹配的内容(如果还有的话)将留在输入流中等待下一个cin语句读取.如果输入与预期不匹配时,那么cin操作的对象将不会被改变并返回状态0.可用来检查输入是否合法.

单字符输入

  • get(char&)和get() 提供不跳过空白符的单字符输入功能

在有参数和没参数的情况下,get()方法都读取下一个输入字符,即使是不可见字符.get(char&)将输入的字符赋给其参数并返回istream对像(意味着可拼接,如cin.get(c1).get(c2)),get(void)将输入的字符转换为整形再返回.如下是两种方式读取到文件末尾的写法:

char ch;
while(cin.get(ch))
{
    // process...
}

int ch;
while((ch=cin.get())!=EOF)
{
    // process...
}

字符串输入

成员函数getline(),get()都有读取字符串的版本,他们的特征标都相同:

  • istream& get(char*,int,char);

第一次参数表示输入字符串的内存单元地址,第二个参数表示读取的最大字符数(通常要加1用于存储字符串结尾字符),第三个参数表示用于分界的字符串,也就是用于指定停止输入的字符.要是没有第三个参数则默认用换行符用作分界符.
上面get和getline的功能都是一样的,只有一点区别,get会将分解符留在输入流中,而getline则读取分解符并丢弃掉.
其中ignore(int,char)用于读取指定数目的字符或者直到分界符为止,并把读取到的字符串丢弃.

上一篇 下一篇

猜你喜欢

热点阅读