getchar() 、 scanf() 、流与缓冲区
C中的缓冲区一直是debug的重灾区,今天在写一个命令行界面的时候又遇到了这个问题,所以来总结一波。
两函数的不同之处
scanf() 会把 stdinBuff 中的特定格式数据取出,非特定格式数据则会留在stdinBuff 中,比如 while(){ scanf("%c", ); } ,当你输入一个字符串+ 回车的时候,它先存入 stdinBuff 中,之后按char类型从 stdinBuff 取出每个字符,然后在把最后一个输入的 \n 留在 stdinBuff 中;当你输入一个字符+回车,多次输入的时候,它会把每次输入中的\n都留在 stdinBuff 中。
getchar() 会把 stdinBuff 中的第一个字符取出,而把输入的其余数据放入 stdinBuff 中。
两函数的相同之处
都可以从流或者缓冲区中读取数据。当 stdinBuffer 不被置为NULL时,stdin 输入流中数据将存入 stdinBuffer 中,scanf 与 getchar 会优先从stdinBuff 中读取数据;当 stdinBuffer 被置为NULL时,scanf getchar 将从 stdin 输入流中读取数据。
流是什么?具有缓冲功能吗?
流是File *类型对象,它的底层实现是 fopen 等c库函数,并且 scanf 将读取输入流中 \n 之前的数据,所以 stdin 输入流具有和缓冲区一样的缓冲功能。如果想读写数据而不占用空间去缓存它们,则是用 read write 这样的系统调用,因为它们是以字节为单位进行读写而不是以 \n 为读写的结束标志,这样的机制决定了它们直接操作数据而无需将数据缓存。
那么如何清理 stdinBuff中的残余数据呢?
1、getchar() 去吸收 stdinBuff 中的残余数据。[推荐使用]
2、Windows下有C库函数 fflush(stdin) ,但是要注意这个函数很依赖编译器。
3、由于LInux无法用 fflush(stdin) 刷新stdin的缓冲区,所以可利用 setbuf(stdin, NULL) 置 stdin 的 Buffer 为NULL以达到刷新 stdinBuffer 的目的,但是这样也会带来问题:pointer of stdinBuffer 指向了NULL,相当于stdin的缓冲区不存在了,以后都只能从 istream 输入流(类似先进先出的字节队列)中读数据,这不是我们想要的目的,虽然可以清除当前 stdinBuffer 的数据,但是以后读数据都必须从 istream 输入流中读取,有点儿大财小用的意味,而且,从 istream 输入流中读入,输入流 stdin 是行缓冲,本身也会缓存数据(注意,\n也会被存储),而不会立刻丢掉之前存储的数据,这样的结果是你的程序中 gechar() 还是会自动读取到你不想要的数据如 "\n" ,综上所述我并不推荐用 setbuf() 去“刷新”缓冲区。
那么如何清理 stoutBuff 中的残余数据呢?
C库函数 printf( "\n") 以刷新 stdinBuff。它的机制是:标准输出流 stdout 的缓冲区是以 \n 标志的,它会将 \n 与之前的数一并取出存入 stdout 而后打印在屏幕上,如果缓冲区不存在 \n ,由于流也拥有缓冲功能,则会"慢一拍"再显示在屏幕上,具体情况是当程序移交给操作系统时流中的数据将会全部打印到屏幕上,然后清空流中数据并关闭。
题外话
额外说一句,如果在C++中, cin.get() 可以只读入一个字符而避免读入 \n ,这样就不用纠结在缓冲区问题上了,或者使用 <ifstream> 的 flush(stdin) 或者是 cin.clear()方法以刷新输入流。
getchar() 、 scanf() 、流与缓冲区的更多相关文章
- scanf函数读取缓冲区数据的问题
标准I\O的缓冲类型 标准I\O根据不同的应用需求,提供了全缓冲.行缓冲.无缓冲三种缓冲方式. 全缓冲:只有当划定的缓冲区被填满或者数据读取至末尾时,才开始执行I\O操作(执行系统提供的read\wr ...
- JAVA之旅(二十五)——文件复制,字符流的缓冲区,BufferedWriter,BufferedReader,通过缓冲区复制文件,readLine工作原理,自定义readLine
JAVA之旅(二十五)--文件复制,字符流的缓冲区,BufferedWriter,BufferedReader,通过缓冲区复制文件,readLine工作原理,自定义readLine 我们继续IO上个篇 ...
- Java精选笔记_IO流(字符输入输出流、字符文件输入输出流、字符流的缓冲区)
字符流 Reader是字符输入流的基类,用于从某个源设备读取字符 Writer是字符输出流,用于向某个目标设备写入字符 字符流操作文件 字符输入流FileReader,通过此流可以从关联的文件中读取一 ...
- cin.get()、流和缓冲区
大家好,这是我在CSDN的第一篇博客.我是一名学习GIS专业的大学生.我从小开始喜欢编程,可是到现在编程水平却长进不大,依然是菜鸟一个.究其原因,虽然这些年乱七八糟的东西学过不少,但是总的来说还是基础 ...
- IO 流之字符流的缓冲区
缓冲区的出现提高了对数据的读写效率 对应类: BufferedWriter BufferedReader 缓冲区需要结合流才可以使用, 对流的功能进行了增强, 即对流的操作起到装饰作用 使用缓冲区实现 ...
- getchar,scanf以及缓冲区
getchar()是stdio.h中的库函数,它的作用是从stdin流中读入一个字符,也就是说,如果stdin有数据的话不用输入它就可以直接读取了.getch()和getche()是conio.h中的 ...
- 关于cin,getchar(),scanf()的注意事项(转)
问题描述一:(分析scanf()和getchar()读取字符) scanf(), getchar()等都是标准输入函数,一般人都会觉得这几个函数非常简单,没什么特殊的.但是有时候却就是因为使用这些 ...
- DirectSound学习(二)--流式缓冲区
使用流式缓冲方式播放波形音频文件比较复杂,主要原因是在只有一个缓冲区提供给用户的前提下,这个缓冲区在提供给声卡播放数据的同是还需要用户不断的定时向其中写入数据.要注意从缓冲区这时是一个环形缓冲区,声音 ...
- getchar(),scanf(),gets(),cin,输入字符串
#include<iostream>#include<stdio.h>#include<string.h>#include<string>using n ...
随机推荐
- 基于MyBatis的数据服务接口
背景 作为软件系统开发,数据操作是系统开发不可避免的一个重要组成部分.因为其重要性围绕着数据操作也出现了众多框架.成熟框架是为了普适众多数据操作要求的,因此为了更好的实现技术落地,需要对框架进行丰富和 ...
- 深入理解立即执行函数(function(){})();
( function(){-} )()和( function (){-} () )是两种javascript立即执行函数的常见写法,要理解立即执行函数,需要先理解一些函数的基本概念. 1,函数声明,函 ...
- NETStandard,NETFx,Mono,NETCore,ASPNetCore 之间关系的整理
因为现在很多人对这几者之间的关系还不甚了解,这里根据我所知来做一个大概的介绍...... .NET Standard: .NET标准,只要符合这个标准实现类库,即可在支持此标准的Run ...
- 十六、Hadoop学习笔记————Zookeeper实战
所有服务器都会先将自己的服务器信息注册到servers中,然后每台服务器都会尝试注册master,哪台注册成功,则哪台就是master服务器. 所有的服务器都会关注master节点的删除事件,这样通过 ...
- ##5.2 Nova计算节点-- openstack pike
##5.2 Nova计算节点 openstack pike 安装 目录汇总 http://www.cnblogs.com/elvi/p/7613861.html ##5.2 Nova计算节点 # co ...
- Go语言教程5 if switch select
首先您需要有php或是c的基础. 否则可能看不明白 方法如下 if 表达式{ //需要注意的是 没有括号. 没错. 没有括号 比如 if 1>2 {}else{} } else { } s ...
- ERROR: unable to bind listening socket for address ’127
ERROR: unable to bind listening socket for address '127.0.0.1:9000′ 解决办法: killall php-fpm 然后重启即可. 我的 ...
- SpringBoot集成Redis实现缓存处理(Spring AOP实现)
第一章 需求分析 计划在Team的开源项目里加入Redis实现缓存处理,因为业务功能已经实现了一部分,通过写Redis工具类,然后引用,改动量较大,而且不可以实现解耦合,所以想到了Spring框架的A ...
- Linux多线程编程——线程的同步
POSIX信号量 posix信号量不同于IPC中的信号量 常用的posix信号量函数 #include <semaphore.h> int sem_init(sem_t* sem,i ...
- PHP运算符优先级 运算符分类
运算符 运算符是可以通过给出的一或多个值(用编程行话来说,表达式)来产生另一个值(因而整个结构成为一个表达式)的东西. 运算符可按照其能接受几个值来分组.一元运算符只能接受一个值,例如 !(逻辑取反运 ...