C语言中输入输出流与缓冲区的深入讲解

前言

缓冲区 又称为缓存,它是内存空间的一部分。也就是说,在内存空间中预留了一定的存储空间,这些存储空间用来缓冲输入或输出的数据,这部分预留的空间就叫做缓冲区。

缓冲区根据其对应的是输入设备还是输出设备,分为输入缓冲区和输出缓冲区。

原理介绍:

  • 当调用输入函数scanf()时,输入函数会将我们输入的数字输入到输入缓冲区,
  • 而当我们的输入缓冲区有内容时,再次输入将不会被执行,
  • 而是直接跳过执行,将输入缓冲区的内容赋给变量;

1、为什么要引入缓冲区

例如,我们从磁盘里取信息,我们先把读出的数据放在缓冲区,计算机再直接从缓冲区中取数据,等缓冲区的数据取完后再去磁盘中读取,这样就可以减少磁盘的读写次数,再加上计算机对缓冲区的操作大大快于对磁盘的操作,故应用缓冲区可大大提高计算机的运行速度。

又比如,我们使用打印机打印文档,由于打印机的打印速度相对较慢,我们先把文档输出到打印机相应的缓冲区,打印机再自行逐步打印,这时我们的CPU可以处理别的事情。

现在您基本明白了吧,缓冲区就是一块内存区, 它用在输入输出设备和CPU之间,用来缓存数据 。它 使得低速的输入输出设备和高速的CPU能够协调工作 ,避免低速的输入输出设备占用CPU,解放出CPU,使其能够高效率工作。

2、缓冲区的类型

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

1) 全缓冲

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

2) 行缓冲

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

3) 不带缓冲

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

3、缓冲区的大小

如果我们没有自己设置缓冲区的话,系统会默认为标准输入输出设置一个缓冲区,这个缓冲区的大小通常是 512个字节 的大小。

缓冲区大小由 stdio.h 头文件中的宏 BUFSIZ 定义,如果希望查看它的大小,包含头文件,直接输出它的值即可:printf("%d", BUFSIZ);

缓冲区的大小是可以改变的,也可以将文件关联到自定义的缓冲区,详情可以查看 setvbuf() setbuf() 函数。

4、缓冲区的刷新(清空)

下列情况会引发缓冲区的刷新: 缓冲区满时 ; 行缓冲区遇到回车时 ; 关闭文件 ; 使用特定函数刷新缓冲区 。

5、结合缓冲区谈谈C语言getchar()、getche()、getch()的区别

先来看一下 getchar() ,其原型为: int getchar(void);

当程序调用getchar()函数时,程序就等着用户按键, 用户输入的字符被存放在键盘缓冲区中,直到用户按回车为止(回车字符也放在缓冲区中) 。当用户键入回车之后,getchar()函数 才开始从键盘缓冲区中每次读入一个字符 。也就是说, 后续的getchar()函数调用不会等待用户按键,而直接读取缓冲区中的字符,直到缓冲区中的字符读完后,才重新等待用户按键 。打个比方,键盘缓冲区就像是一条水管连着你的程序,程序调用getchar()函数用户输入字符就相当于往水管里注水,这个水注多少取决于你输入多少,当你按回车停止注水时,getchar()函数才会开始从键盘缓冲区,也就是我们的水管里取水,那每次只会读一个字符也就是每次取一定量的水,当你在这之后继续调用getchar()函数时,会接着在水管里取上次没用完的水,因为你的水管没清空(缓冲区的刷新),那这个阶段就不用你再输入了,因为一调用getchar()函数就有水可取嘛,直到水管里没水了,你还调用getchar()函数,那这个时候你就得注水了也就是程序会等你按键。

通俗一点说,当程序调用getchar()函数时,程序就等着用户按键,并等用户按下回车键返回。期间按下的字符存放在缓冲区,第一个字符作为函数返回值。继续调用getchar()函数,将不再等用户按键,而是返回您刚才输入的第2个字符;继续调用,返回第3个字符,直到缓冲区中的字符读完后,才等待用户按键。

getchar()函数的执行就是采用了行缓冲。第一次调用getchar()函数,会让程序使用者(用户)输入一行字符并直至按下回车键 函数才返回。此时用户输入的字符和回车符都存放在行缓冲区。再次调用getchar()函数,会逐步输出行缓冲区的内容。

请看下面一个例子:

运行结果如下:

再把程序做微小改变,你再看看,加深理解:

运行结果:

上面第二次打印时不是2而是空格,你应该想到为什么了吧?

好,我们再来看一个例子:

运行结果:

getchar()函数是从 输入流缓冲区 中读取数据的,而不是从 键盘(终端)缓冲区 读取。当读取遇到回车(\n)结束时,这个'\n'会一起读入到输入流缓冲区的, 所以第一次接收输入时取走字符后会留下字符\n,这样第二次getchar()直接从缓冲区中把\n取走了 ,显然读取成功了,所以不会再从终端读取!其实这里的 10恰好是回车符 !这就是为什么这个程序只执行了一次输入操作就结束的原因!

getch()和getche()函数

在TC2.0时代,C程序员总是喜欢在程序末尾加上getch() ,来实现程序运行完了暂停不退出的效果。如果不这样做,在TC2.0的环境中Ctrl+F9编译并运行后会立即退出程序,根本来不及看到结果。这时如果要看结果,就要按Alt+F5回到DOS环境中去,很麻烦。而如果在程序的结尾加上一行getch();语句,就可以省掉回DOS看结果这个步骤,因为程序运行完了并不退出,而是在程序最后把屏幕停住了,按任意键才退出程序。

实际上, getch() 的作用是从键盘 接收一个字符,且不带回显 。就是说, 你按了一个键后它并不在屏幕上显示你按的什么,而继续运行后面的代码 ,所以在C语言中可以用它来实现“按任意键继续”的效果,即程序中遇到getch();语句,就会停下来,等你按任意键,它接收了这个字符键后再继续执行后面的代码。这跟上面在Windows下用的system(“PAUSE")功能一样,但却不会在屏幕上显示(即不会有”按任意键继续“的提示),这样,利用getch()无回显的特性,不管你按什么键,都不会在屏幕上留下痕迹,使你的界面达到美观效果。。

getche()getch()很相似,它也需要引入头文件conio.h,它们之间的区别就在于:getch()无回显,getche()有回显。

下面看一个例子:

首先这是个连续5次的循环来实现5次停顿,等待你输入。编译并运行这个程序,假设输入的是abcde,那么屏幕上显示的结果也是abcde,这个abcde并不是在ch=getch();中输出的。把printf("%c",ch);这行语句去掉,就会发现按5次任意键程序就结束了,但屏幕上什么都没有显示。

你可以把代码中的getch()换成getche()看看有什么不同。如果还是输入abcde,那么屏幕上显示的结果是aabbccddee,我们把printf("%c",ch);这行语句再去掉,显示的结果就是abcde了,说明程序在执行ch=getche();这条语句的时候就把我们输入的键返回显示在屏幕上, 有无回显就是它们的唯一区别 。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • C语言中printf()缓冲问题详解

    前言 缓冲区又称为缓存,它是内存空间的一部分.也就是说,在内存空间中预留了一定的存储空间,这些存储空间用来缓冲输入或输出的数据,这部分预留的空间就叫做缓冲区. 缓冲区根据其对应的是输入设备还是输出设备,分为输入缓冲区和输出缓冲区. 为什么要引入缓冲区 比如我们从磁盘里取信息,我们先把读出的数据放在缓冲区,计算机再直接从缓冲区中取数据,等缓冲区的数据取完后再去磁盘中读取,这样就可以减少磁盘的读写次数,再加上计算机对缓冲区的操作大大快于对磁盘的操作,故应用缓冲区可大大提高计算机的运行速度. 又比如,

  • C语言中字符的输入输出以及计算字符个数的方法详解

    C语言字符输入与输出 标准库提供的输入/输出模型非常简单.无论文本从何处输入,输出到何处,其输入/输出都是按照字符流的方式处理.文本流是由多行字符构成的字符序列,而每行字符则由 0 个或多个字符组成,行末是一个换行符.标准库负责使每个输入/输出流都能够遵守这一模型.使用标准库的 C 语言程序员不必关心在程序之外这些行是如何表示的. 标准库提供了一次读/写一个字符的函数,其中最简单的是 getchar 和 putchar 两个函数.每次调用时,getchar 函数从文本流中读入下一个输入字符,并将

  • C语言数据输入与输出实例详解

    C语言数据输入与输出实例详解 1 概论 C语言提供了跨平台的数据输入输出函数scanf()和printf()函数,它们可以按照指定的格式来解析常见的数据类型,例如整数,浮点数,字符和字符串等等.数据输入的来源可以是文件,控制台以及网络,而输出的终端可以是控制台,文件甚至是网页. 2 数据输出 从第一个c语言程序中,就使用了跨平台的库函数printf实现将一段文字输出到控制台,而实际上,printf()不仅可以将数据按照指定的格式输出到控制台,还可以是网页或者是指定的文件中,printf()函数执

  • C语言格式化输入输出函数详解

    一:格式输出函数printf() 1.调用形式一般为:printf("格式化控制字符串",输出表列): 2.格式化控制字符串用于指定输出格式,它有三种形式: 1.格式说明符:规定了相应输出表列内容的输出格式,以%打头,如%d.%o等 2.转义字符:用来输出转义字符所代表的控制代码或者特殊字符,比如常用的'\n'.'\t' 3.普通字符:需要原样输出的字符. 3.输出表列为若干需要输出的数据项,它与格式说明符在数量和类型上一一对应: 4.格式字符m指定输出数据所占宽度,n对实数表示输出n

  • C语言中输入输出流与缓冲区的深入讲解

    前言 缓冲区 又称为缓存,它是内存空间的一部分.也就是说,在内存空间中预留了一定的存储空间,这些存储空间用来缓冲输入或输出的数据,这部分预留的空间就叫做缓冲区. 缓冲区根据其对应的是输入设备还是输出设备,分为输入缓冲区和输出缓冲区. 原理介绍: 当调用输入函数scanf()时,输入函数会将我们输入的数字输入到输入缓冲区, 而当我们的输入缓冲区有内容时,再次输入将不会被执行, 而是直接跳过执行,将输入缓冲区的内容赋给变量; 1.为什么要引入缓冲区 例如,我们从磁盘里取信息,我们先把读出的数据放在缓

  • 浅谈JAVA中输入输出流实例详解

    java语言的输入输出功能是十分强大而灵活的,美中不足的是看上去输入输出的代码并不是很简洁,因为你往往需要包装许多不同的对象.在Java类库中,IO部分的内容是很庞大的,因为它涉及的领域很广泛:标准输入输出,文件的操作,网络上的数据流,字符串流,对象流,zip文件流....本文的目的是为大家介绍JAVA中输入输出流实例详解. 流的层次结构 定义:        java将读取数据对象成为输入流,能向其写入的对象叫输出流.结构图如下: 1.输入输出: 输入/输出(Input/Output)是指对某

  • C++中输入输出流及文件流操作总结

    本文实例为大家分享了C++中输入输出流及文件流操作笔记,供大家参考,具体内容如下 1.流的控制 iomanip          在使用格式化I/O时应包含此头文件.     stdiostream   用于混合使用C和C + +的I/O机制时,例如想将C程序转变为C++程序 2.类继承关系 ios是抽象基类,由它派生出istream类和ostream类, iostream类支持输入输出操作,iostream类是从istream类和ostream类通过多重继承而派生的类 类ifstream继承了

  • 在C语言中输入中文字符串讲解

    C语言中的字符串是以ASCII码表的形式存入的,输入英文字符是以英文字符对应的ASCII码的形式进入寄存器中的,例如输出hello world!: 将c反汇编得到, 可以看到h的ASCII码是68,e的ASCII码是65等等存放进内存的,那中文字呢?中文字并没有对应的ASCII码,还可以显示出来吗? 答案当然是肯定的,在计算机中存储中文使用的编码规则是GB2312或GB2312-80,规定:一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字,这样我们就可以组合

  • C语言中结构体的内存对齐规则讲解

    目录 1.结构体的内存对齐规则 2.例子 3.为什么存在内存对齐 4.如何修改默认对齐数 1.结构体的内存对齐规则 1.第一个成员在与结构体变量偏移量为0的地址处. 2.其他成员变量都放在对齐数(成员的大小和默认对齐数的较小值)的整数倍的地址处. 对齐数=编译器默认的一个对齐数与该成员大小的较小值.(VS中默认的对齐数是8) 3.结构体总大小为最大对齐数(每个成员变量都有一个对齐数 )的整数倍. 4.如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最

  • C语言中注释与注意事项的深入讲解

    C语言注释简介: 注释应该出现在三种位置 文件头部 函数头部 函数体内的和代码混在一起的注释 对于文件头部的注释至少列出: 版权声明.版本号.文件创建日期.作者.内容/功能.与其他文件的关系.修改日志等. 函数头部注释要求至少列出: 函数功能.输入/输出参数.返回值.调用/被调用关系等. C语言注释实例 注释在预编译阶段就会被删除掉,但是这里的删除并不是字面意义的删除,而是被替换,注释被替换,本质是替换成空格. 以下面的代码为例: #include <stdio.h> int main() {

  • C语言中的字符(char)详细讲解

    1.字符型(char)简介 字符型(char)用于储存字符(character),如英文字母或标点. 严格来说,char 其实也是整数类型(integer type),因为 char 类型储存的实际上是整数,而不是字符. 计算机使用特定的整数编码来表示特定的字符. 2. 声明字符型变量 3. 字符常量与初始化 实例: 用 char 类型来专门表示一个字符,例如: char a='1'; char b='$'; char c='X'; char d=' '; // 空格也是一个字符 char e=

  • 解决C语言中使用scanf连续输入两个字符类型的问题

    昨天用C编程,遇到一个关于scanf的细节问题,假如运行如下程序: #include<stdio.h> int main() { char ch1,ch2; printf("Input for ch1:/n"); scanf("%c",&ch1); printf("ch1=%c/n",ch1); printf("Input for ch2:/n"); scanf("%c",&ch

  • C语言实现输入一个字符串后打印出该字符串中字符的所有排列

    本文实例讲述了C语言实现输入一个字符串后打印出该字符串中字符的所有排列的方法,属于数学里的排列问题.是一个很实用的算法技巧.分享给大家供大家参考.具体实现方法如下: 例如输入字符串abc,则输出由字符a.b.c所能排列出来的所有字符串abc.acb.bac.bca.cab和cba. C语言实现代码如下: /* * Copyright (c) 2011 alexingcool. All Rights Reserved. */ #include <iostream> #include <al

  • Go语言中关闭带缓冲区的频道实例分析

    本文实例分析了Go语言中关闭带缓冲区的频道.分享给大家供大家参考.具体分析如下: Go语言提供了两种频道,带缓冲区和不带缓冲区的.不带缓冲区的频道,发送和接收是同步的,必须接收端接收了消息,发送端才能从发送调用中解脱.带缓冲区的频道,在缓冲区满之前,发送和接收是异步的,发送端的发送操作只保证把消息放入缓冲区. Go的频道是可以关闭的,关闭频道的目的是让接收端知道不会再有消息从这个频道进入,我们可能会用某个频道的关闭来表示某种状态的终结. 当我们关闭一个带缓冲区的频道时,如果缓冲区中还有消息,接收

随机推荐