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 ...
随机推荐
- JavaScript高级程序设计之自学笔记(一)————Array类型
以下为自学笔记. 一.Array类型 创建数组的基本方式有两种: 1.1第一种是使用Array构造函数(可省略new操作符). 1.2第二种是使用数组字面量表示法. 二.数组的访问 2.1访问方法 在 ...
- centos6.7安装openblas错误
centos系统:CentOS release 6.7 (Final)安装OpenBLAS # Install OpenBLAS at /usr/local/openblas git clone ht ...
- _1Python简介 安装及版本检测
简介 Python是一种面向对象的解释性计算机程序设计语言,由荷兰人Guido von Rossum于1988年的圣诞节发明,第一个公开发行版于1991年. Python崇尚优美.清晰.简单,是一个优 ...
- 一个高性能异步socket封装库的实现思路 (c#)
前言 socket是软件之间通讯最常用的一种方式.c#实现socket通讯有很多中方法,其中效率最高就是异步通讯. 异步通讯实际是利用windows完成端口(IOCP)来处理的,关于完成端口实现原理, ...
- You may rarely look at it. But you'll always feel it
You may rarely look at it. But you'll always feel it
- ASP.NET没有魔法——ASP.NET Identity 的“多重”身份验证
ASP.NET Identity除了提供基于Cookie的身份验证外,还提供了一些高级功能,如多次输入错误账户信息后会锁定用户禁止登录.集成第三方验证.账户的二次验证等,并且ASP.NET MVC的默 ...
- 【ASP.NET Core】运行原理之启动WebHost
ASP.NET Core运行原理之启动WebHost 本节将分析WebHost.CreateDefaultBuilder(args).UseStartup<Startup>().Build ...
- ThinkPHP中ajax绑定select下拉框无法显示
html代码: 控制器代码: 其中的<option value="{$vo.gradeId}">{$one.gradeName}</option> 在操作过 ...
- mysql常用的操作
数据库的常用操作:create database db1; #创建数据库show databases; #查看所有数据库show create database db1;#查看创建的指定数据库alte ...
- 为什么win记事本编辑的shell在linux中运行会报错
结论:win记事本使用的格式有别于linux,二者不可混用.linux使用一个叫vi的编辑器. 解决办法:使用vi命令建立文件,在其中敲shell.命令:vi > filename (敲完 ...