C/C++中关于输入输出缓冲区和流的概念理解

(本文章关于缓冲区概念的理解部分取自:http://developer.51cto.com/art/201107/277186.htm)

  首先可以看下快递的寄送过程:

  源地址(商家的仓库)——中转地(快递公司的仓库)——目的地(买家)

  我们从淘宝商家买衣服,商家通过快递公司把商品送到我们手里的这个过程可以形象的解释下缓存区和流的这个概念。

  1, 淘宝商家不会亲自把商品给买家送过来的,因为这样效率太低了,商家会通过快递公司这个中转,然后快递公司再把东西送给买家。淘宝商家就是在键盘上打字,买家就是程序,程序需要读取从键盘上的输入的字,缓冲区就是快递公司的仓库。

  2, 商品的几种位置状态:商家仓库,快递仓库,买家手中,还有一种状态就是在路上。输入输出的流就是指的在路上。

  3, 快递收货员收到商品就放到自己的中转仓库中。但是快递公司肯定等仓库中的商品积累到一定程度才开始派送。行缓冲就是遇到换行符时就认为需要执行I/O操作了。

一,缓冲区的概念

  缓冲区又可以称为缓存。计算机中的内存可以被认为是硬盘的缓存。当cpu读取文件、执行程序时,不会直接从硬盘中读取,而是先把文件缓存到内存中,然后再从内存中读取。

  对于C++程序来说,当类似cin,getchar这样的对象或者函数读取输入时,不会直接直接读键盘上的输入,而是这样的一个过程:cin——输入缓冲区——键盘。我们从键盘上输入的字符先存到缓冲区里面,cin从缓冲区里面读取输入。对于输出来说,程序的结果不会直接显示到屏幕上,而是先存放到缓冲区,然后cout把内容从缓冲区输出到屏幕。cin和cout本质上都是对缓冲区中的内容进行操作。

  如果没有缓冲区就会大大降低CPU的效率,因为cpu将不得不一直等待用户的输入,而不能执行其他的操作,人打字输入的速度再快,也比不上CPU的执行速度,人在输入两个字符之间的间隔时间,cpu完全可以去干别的事情。

  缓冲区分为三种全缓冲、行缓冲和不带缓冲。

  1、全缓冲

  在这种情况下,当填满标准I/O缓存后才进行实际I/O操作。全缓冲的典型代表是对磁盘文件的读写。

  2、行缓冲

  在这种情况下,当在输入和输出中遇到换行符时,执行真正的I/O操作。这时,我们输入的字符先存放在缓冲区,等按下回车键换行时才进行实际的I/O操作。典型代表是键盘输入数据。

  3、不带缓冲

  也就是不进行缓冲,标准出错情况stderr是典型代表,这使得出错信息可以直接尽快地显示出来。

  缓冲区的刷新指的是缓冲区的内容被清空刷新,这也就意味着刷新之前系统会对缓冲区内容进行I/O读写。下面4种情况会触发缓冲区的刷新:

  缓冲区满时;

  执行flush语句;

  执行endl语句;

  关闭文件。

  C/C++程序里面的缓冲区指的是为标准输入与标准输出设置的缓冲区,如果我们不认为的设置的话,系统会自动的为标准输入与标准输入设置一个缓冲区,这个缓冲区的大小通常是4Kb的大小。

  ANSI C要求下列缓存特征:

  (1) 当且仅当标准输入和标准输出并不涉及交互作用设备(键盘,屏幕)时,它们才是全缓存的。 读写文件的时候就是全缓存。

  (2)标准出错决不会是全缓存的。

  (3)标准输入和输出涉及交互作用设备时,虽然没有明确规定是不带缓存的还是行缓存的,但一般系统默认它们是行缓存的。

  因此我们经常要用的标准输入和输出,stdin、stdout和stderr的缓存特征是:stdin和stdout是行缓存;而stderr是无缓存的。cin和cout都是从缓冲区读取

  二、流的概念

  流是一个过程,一个动态的概念。可以把流想象成水在水管中流动的过程,想象成商品快递运送的过程。cin和cout就是执行流这个过程的人。

  对于输入,cin负责把输入缓冲区中的内容传递给程序;

  对于输出,cout负责把输出缓冲区中的内容传递给屏幕。

  cin和cout把缓冲区的数据变成流,然后搬运到相应的目的地。cin和cout就是个搬运工,搬运的过程就是流。

三、代码案例
      第一段代码:

int main()
{
    string str;
    int i=0;
    while (cin >> str)
    {
        cout << str<<endl;
        cout << ++i << endl;
    }
    return 0;
}
程序执行过程中输入:i love you
最终结果是:
i
1
love
2
you
3

  执行过程中,程序并不会在每次输入一个空格时就打印一次,而在在完全输入一行字符串并摁下回车后,才会打印。原因就是在我们输入回车之前的一行字符串都只是存放到了为标准输入分配的缓冲区中,这是一个行缓冲区,在遇到换行符之前,缓冲区不会刷新也就不会触发I/O操作,cin也就没有在读取数据。输入回车后,cin开始执行I/O操作,读取缓冲区中的字符:首先读取i,然后遇到了空格,此次读取完成,执行循环。然后接着读取love,又遇到了空格,读取完成,执行循环。最后读取了you。
  第二段代码:

int main()
{
    char c;
    //第一次调用getchar()函数
    //程序执行时,您可以输入一串字符并按下回车键,按下回车键后该函数才返回
    c = getchar();
    //显示getchar()函数的返回值
    cout << c << endl;
    //暂停
    system("PAUSE");
    //循环多次调用getchar()函数
    //将每次调用getchar()函数的返回值显示出来
    //直到遇到回车符才结束
    while ((c = getchar()) != ‘\n‘)
    {
        printf("%c", c);
    }
    //暂停
    system("PAUSE");
    return 0;
}
执行程序,输入:abcdefg,然后回车
程序结果如下:
a
bcdefg

  第一次执行到getchar时,由于此时缓冲区里面没有任何内容,所以程序等待键盘的输入,输入abcdefg后,然后输入回车,触发了行缓冲的条件,执行I/O,getchar开始读取缓冲区的内容,由于此函数只读取一个字符,所以读完字符a后,读取结束,执行下面的语句,将a打印到屏幕。由于缓冲区中字符只被读取了1个字符a,剩余的bcdefg还在缓冲区中,因此执行到while中的getchar时,直接读取缓冲区中的内容,也就是依次读取bcdefg,回车符也是缓冲区中的一个字符,当读取完回车后,while循环结束。

时间: 2024-11-03 03:36:57

C/C++中关于输入输出缓冲区和流的概念理解的相关文章

c语言输入输出缓冲区的概念

语言输入输出缓冲区的概念 你肯定会奇怪为什么一开始先说这个,一开始不都是数据类型什么的嘛,这个写在最前面因为后面的程序即使最简单的code都会用到输入输出,输出比较简单,可以放在后面再说,但是输入就不同了,如果不先了解一下,可能会得到和你预想不同的结果哦^_^.也正是由于和一般的c语言介绍方式不同,为了看起来正规一些,我就把这章叫做chapter0了,完全可以先跳过去,直接看chapter1. 1.getchar 先引用一下前人的成果(有修改)^_^:http://blog.csdn.net/c

c/c++ 输入输出缓冲区

关于缓冲区的详细介绍,请参考 C++编程对缓冲区的理解 CPP的输入输出流和缓冲区 c++输出缓冲区刷新 (1)c++中cin.cout,cerr和c的stdin.stdout.stderr都是同步的,即iostream 对象和 and cstdio流是同步的,同步关系如下: 同步即表明我们可以在程序中混合用cout和printf或其他对应的流对.可以用std::ios_base::sync_with_stdio(false)来取消这种同步,取消后,如下程序中cout和printf就不是按照预期

Java知多少(66)输入输出(IO)和流的概述

输入输出(I/O)是指程序与外部设备或其他计算机进行交互的操作.几乎所有的程序都具有输入与输出操作,如从键盘上读取数据,从本地或网络上的文件读取数据或写入数据等.通过输入和输出操作可以从外界接收信息,或者是把信息传递给外界.Java把这些输入与输出操作用流来实现,通过统一的接口来表示,从而使程序设计更为简单. Java流的概念 流(Stream)是指在计算机的输入输出操作中各部件之间的数据流动.按照数据的传输方向,流可分为输入流与输出流.Java语言里的流序列中的数据既可以是未经加工的原始二进制

C++中输入输出流及文件流操作笔记

1.流的控制 iomanip          在使用格式化I/O时应包含此头文件.    stdiostream   用于混合使用C和C + +的I/O机制时,例如想将C程序转变为C++程序 2.类继承关系 ios是抽象基类,由它派生出istream类和ostream类, iostream类支持输入输出操作,iostream类是从istream类和ostream类通过多重继承而派生的类 类ifstream继承了类istream,类ofstream继承了类ostream,类fstream继承了

关于C中I/O缓冲区的解释

用户程序调用C标准I/O库函数读写文件或设备,而这些库函数要通过系统调用把读写请求传给内核,最终由内核驱动磁盘或设备完成I/O操作.C标准库为每个打开的文件分配一个I/O缓冲区以加速读写操作,通过文件的FILE结构体可以找到这个缓冲区,用户调用读写函数大多数时候都在I/O缓冲区中读写,只有少数时候需要把读写请求传给内核.以fgetc/fputc为例,当用户程序第一次调用fgetc读一个字节时,fgetc函数可能通过系统调用进入内核读1K字节到I/O缓冲区中,然后返回I/O缓冲区中的第一个字节给用

1.java.io包中定义了多个流类型来实现输入和输出功能,

1.java.io包中定义了多个流类型来实现输入和输出功能,可以从不同的角度对其进行分 类,按功能分为:(C),如果为读取的内容进行处理后再输出,需要使用下列哪种流?(G)   A.输入流和输出流 B.字节流和字符流 C.节点流和处理流   D.File stream E.Pipe stream F.Random stream G.Filter stream

转:&quot;在已损坏了程序内部状态的XXX.exe 中发生了缓冲区溢出&quot;的一种可能原因

我的问题跟原作者的问题差不多.头文件和DLL不匹配导致的. 原文链接:http://blog.csdn.net/u012494876/article/details/39030887 今天软件突然出现崩溃的bug: 在release模式下,总是崩溃在一个函数A的结束处,打印输出调试,发现如果注释该函数A中的某个函数B的调用,崩溃不会发生:除此之外,注释函数B中的任何代码都不起作用. 崩溃时弹出的对话框为:"在已损坏了程序内部状态的 BREW_Simulator.exe 中发生了缓冲区溢出.按“中

《算法竞赛入门经典》学习笔记 2.4.4 C++中的输入输出

2.4.3 64位整数输入输出long long除了cin,cout,也可以借助于printf和scanf语句,但对应的占位符缺是和平台与编译器相关的:在Linux中,gcc很同意的用%lld:在Windows中,MinGW的gcc和VC6都需要用%I64d:但VS2008却是用%lld.2.4.4 C++中的输入输出问题是经典的“A+B”问题:输入若干对整数,输出每对之和.第1种方法: #include <cstdio> //功能和C中的stdio.h很接近,但有些许不同 using nam

如何处理Android中的防缓冲区溢出技术

[51CTO专稿]本文将具体介绍Android中的防缓冲区溢出技术的来龙去脉. 1.什么是ASLR? ASLR(Address space layout randomization)是一种针对缓冲区溢出的安全保护技术,通过对堆.栈.共享库映射等线性区布局的随机化.通过添加攻击者预測目的地址的难度.防止攻击者直接定位攻击代码位置,达到阻止溢出攻击的目的.通常情况下.黑客会利用某个特定函数或库驻存在特定内存位置的这一事实.通过在操纵堆或其它内存错误时调用该函数来发动攻击.ASLR则可以避免这样的情况