当前位置: 首页 > 编程日记 > 正文

C语言清空输入缓冲区的N种方法对比

C语言中有几个基本输入函数:

//获取字符系列
int fgetc(FILE *stream);
int getc(FILE *stream);
int getchar(void);
//获取行系列
char *fgets(char * restrict s, int n, FILE * restrict stream);
char *gets(char *s);//可能导致溢出,用fgets代替之。
//格式化输入系列
int fscanf(FILE * restrict stream, const char * restrict format, …);
int scanf(const char * restrict format, …);
int sscanf(const char * restrict str, const char * restrict format, …);
这里仅讨论输入函数在标准输入(stdin)情况下的使用。纵观上述各输入函数,
  • 获取字符系列的的前三个函数fgetc、getc、getchar。以getchar为例,将在stdin缓冲区为空时,等待输入,直到回车换行时函数返回。若stdin缓冲区不为空,getchar直接返回。getchar返回时从缓冲区中取出一个字符,并将其转换为int,返回此int值。

MINGW 4.4.3中FILE结构体源码

typedef struct _iobuf
{
	char*	_ptr;//指向当前缓冲区读取位置
	int	_cnt;//缓冲区中剩余数据长度
	char*	_base;
	int	_flag;
	int	_file;
	int	_charbuf;
	int	_bufsiz;
	char*	_tmpfname;
} FILE;
各编译器实现可能不一样,这里获取字符系列函数只用到_ptr和_cnt。

MINGW 4.4.3中getchar()实现

__CRT_INLINE int __cdecl __MINGW_NOTHROW getchar (void)
{
  return (--stdin->_cnt >= 0)
    ?  (int) (unsigned char) *stdin->_ptr++
    : _filbuf (stdin);
}

其中stdin为FILE指针类型,在MINGW 4.4.3中,getc()和getchar()实现为内联函数,fgetc()实现为函数。顺便说一句,C99标准中已经加入对内联函数的支持了。

  • 获取行系列的fgets和gets,其中由于gets无法确定缓冲区大小,常导致溢出情况,这里不推荐也不讨论gets函数。对于fgets函数,每次敲入回车,fgets即返回。fgets成功返回时,将输入缓冲区中的数据连换行符’\n’一起拷贝到第一个参数所指向的空间中。若输入数据超过缓冲区长度,fgets会截取数据到前n-1(n为fgets第二个参数,为第一个参数指向空间的长度),然后在末尾加入’\n’。因此fgets是安全的。通常用fgets(buf, BUF_LEN, stdin);代替gets(buf);。
  • 格式化输入系列中,fscanf从文件流进行格式化输入很不好用。常用的还是scanf,格式化输入系列函数舍去输入数据(根据函数不同可能是标准输入也可能是字符串输入,如:sscanf)前的空白字符(空格、制表符、换行符)直至遇到非空白字符,然后根据格式参数尝试对非空白字符及后续字符进行解析。该系列函数返回成功解析赋值的变量数,若遇文件尾或错误,返回EOF。

=================分 割 线=================

提到缓冲区,就不得不提setbufsetvbuf两个缓冲区设置函数,其声明如下:

void setbuf(FILE * restrict stream, char * restrict buf);
int setvbuf(FILE * restrict stream, char * restrict buf, int mode, size_t size);

setvbuf的mode参数有:

  • _IOFBF(满缓冲):缓冲区空时读入数据;缓冲区满时向流写入数据。
  • _IOLBF(行缓冲):每次从流读入一行数据或向流写入数据。如:stdio,stdout
  • _IONBF(无缓冲):直接从流读入数据,或者直接向流写入数据,而没有缓冲区。如:stderr

setbuf(stream, buf);在:

  • buf == NULL:等价于(void)setvbuf(stream, NULL, _IONBF, 0);
  • buf指向长度为BUFSIZ的缓冲区:等价于(void)setvbuf(stream, buf, _IOFBF, BUFSIZ);

注:BUFSIZ宏在stdio.h中定义。

这里还要提一下传说中的setbuf经典错误,在《C陷阱和缺陷》上有提到:

int main()
{
    int c;
    char buf[BUFSIZ];
    setbuf(stdout,buf);
    while((c = getchar()) != EOF)
        putchar(c);
    
    return 0;
}

问题是这样的:程序交回控制给操作系统之前C运行库必须进行清理工作,其中一部分是刷新输出缓冲,但是此时main函数已经运行完毕,buf缓冲区作用域在main函数中,此时buf字符数组已经释放,导致输出诡异乱码。

解决方案:可以将buf设置为static,或者全局变量,或者调用malloc来动态申请内存。

=================分 割 线=================

下面来看看几种流行的缓冲区清空方法:

  • fflush(stdin);式

由C99标准文档中:

If stream points to an output stream or an update stream in which the most recent
operation was not input, the fflush function causes any unwritten data for that stream
to be delivered to the host environment to be written to the file; otherwise, the behavior is
undefined.

可以看出fflush对输入流为参数的行为并未定义。但由MSDN上的fflush定义:

If the file associated with stream is open for output, fflush writes to that file the 
contents of the buffer associated with the stream. If the stream is open for input, 
fflush clears the contents of the buffer. 

可以看出fflush(stdin)在VC上还是有效地!鉴于各编译器对fflush的未定义行为实现不一样,不推荐使用fflush(stdin)刷新输入缓冲区。

  • setbuf(stdin, NULL);式

由前面对setbuf函数的介绍,可以得知,setbuf(stdin, NULL);是使stdin输入流由默认缓冲区转为无缓冲区。都没有缓冲区了,当然缓冲区数据残留问题会解决。但这并不是我们想要的。

  • scanf("%*[^\n]");式(《C语言程序设计 现代方法 第二版》中提到)

这里用到了scanf格式化符中的“*”,即赋值屏蔽;“%[^集合]”,匹配不在集合中的任意字符序列。这也带来个问题,缓冲区中的换行符’\n’会留下来,需要额外操作来单独丢弃换行符。

  • 经典式
int c;
while((c = getchar()) != '\n' && c != EOF);

由代码知,不停地使用getchar()获取缓冲区中字符,直到获取的字符c是换行符’\n’或者是文件结尾符EOF为止。这个方法可以完美清除输入缓冲区,并且具备可移植性。

原文地址:C语言清空输入缓冲区的N种方法对比

相关文章:

低耗时、高精度,微软提基于半监督学习的神经网络结构搜索算法

作者 | 罗人千、谭旭、王蕊、秦涛、陈恩红、刘铁岩 来源 | 微软研究院AI头条(ID:MSRAsia)编者按:近年来,神经网络结构搜索(Neural Architecture Search, NAS)取得了较大的突破,但仍然面临搜索耗…

《虚拟化与云计算》读书感(三)数据中心的概述

看了《虚拟化与云计算》的第一章第一节‘数据中心的概述’。在我读这一节开始,我看到这个题目的时候总是联想到类似谷歌数据中心一类的东西,多个硬盘或者服务器的堆叠。然后整来几个集装箱把这些堆叠的服务器塞进去,然后供用户使用。然而自从…

golang笔记——struct

1、定义一个结构体 type User struct {userid intusername stringpassword string } 2、初始化一个结构体 有两种情况,一是得到结构体的对象,一是得到结构的对象指针,分别有三种方式: //第1种方式,先声明对象&#x…

posix_memalign

翻译的<Linux system programming> 第八章 二 ;《Linux System Programming》中文版 对齐 数据的对齐(alignment)是指数据的地址和由硬件条件决定的内存块大小之间的关系。一个变量的地址是它大小的倍数的时候&#xff0c;这就叫做自然对齐(naturally aligned)。例如&…

ubuntu 10.04 安装eclipse及其中文语言包

1.安装eclipsesudo apt-get install eclipse2.暗自中文语言包点 击下载中文语言包&#xff08;http://www.eclipse.org/downloads/download.php?file /technology/babel/babel_language_packs/BabelLanguagePack-eclipse- zh_3.5.0.v20091121043401.zip&urlhttp://d2u376u…

世界顶级赛事百万座位如何做到票务限时匹配?

作者 | 阿里文娱技术专家 展恒出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;背景麦座&#xff0c;是大麦旗下的票务系统。去年&#xff0c;我们承接了 2019 年国际篮联篮球世界杯&#xff08;2019FBWC&#xff09;&#xff0c; 核心目标是完成三种套票的运营及售卖…

[转](不理想)Ubuntu下更改主显示器

参考链接&#xff1a;http://www.cnblogs.com/feng_013/archive/2012/03/05/2380111.html 查看显示器信息&#xff1a; fdmfdm-OptiPlex-780:~$ xrandr 设置主显示器 fdmfdm-OptiPlex-780:~$ xrandr --output HDMI1 --auto --primary 设置副显示器在主显示器右边 fdmfdm-OptiPl…

Nginx源码分析--数据对齐posix_memalign和memalign函数

posix_memalign函数() /* * 背景&#xff1a; * 1&#xff09;POSIX 1003.1d * 2&#xff09;POSIX 标明了通过malloc( ), calloc( ), 和 realloc( ) 返回的地址对于 * 任何的C类型来说都是对齐的 * 功能&#xff1a;由posix_memalign分配的内存空间&…

不要一辈子靠技术生存

今天看了一篇文章,感受挺深的,人的一生不能一辈子靠技术生存,尽管你的技术能力很强.(文章转载出处忘记,有哪位朋友知道的提醒一下)一、 在中国你千万不要因为学习技术就可以换来稳定的生活和高的薪水待遇&#xff0c;你千万更不要认为哪些从事 市场开发&#xff0c;跑腿的人&am…

中国顶尖的技术社区们在一个群里,会聊什么…

* 文中表情包图片来自网络

矩阵中路径数目问题

在如下8*6的矩阵中&#xff0c;请计算从A移动到B一共有____种走法。要求每次只能向上或向右移动一格&#xff0c;并且不能经过P。 8*6的矩阵&#xff0c;从左下角A到右上角B&#xff0c;一共需要走12步&#xff0c;其中5步向上&#xff0c;7步向右&#xff0c;因此总的走法一共…

RANet : 分辨率自适应网络效果和性能的best trade-off | CVPR 2020

作者 | VincentLee来源 | 晓飞的算法工程笔记简介深度CNN带来了性能提升的同时也带来了过高的计算量&#xff0c;许多研究放在了如何进行网络加速上面&#xff0c;其中比较直接的是根据样本难易程度进行自动调整的自适应网络。基于对自适应网络的研究&#xff0c;论文提出了自适…

strcpy,memcpy和memmove区别

strcpy和memcpy都是标准C库函数&#xff0c;它们有下面的特点。 strcpy提供了字符串的复制。即strcpy只用于字符串复制&#xff0c;并且它不仅复制字符串内容之外&#xff0c;还会复制字符串的结束符。 已知strcpy函数的原型是&#xff1a;char* strcpy(char* dest, const cha…

WinForm 读写配置文件

读配置文件 方法(1) //ConfigurationManager.RefreshSection("appSettings");stringsettingValue ConfigurationManager.AppSettings.Get("setting1");读配置文件 方法(2) Configuration config ConfigurationManager.OpenExeConfiguration(ConfigurationU…

PHP 读取数据库内容并以二维数组按指定列输出实例

最新PHP 读取数据库内容并以二维数组按指定列输出实例以下是三零网为大家整理的最新PHP 读取数据库内容并以二维数组按指定列输出实例的文章&#xff0c;希望大家能够喜欢!<?php$host "localhost"; //主机名$user "root"; //mysql用户名$passwor…

指针的本质2-void和void*及其应用在nginx中的应用

指针本质论指针有两个属性:指向变量/对象的地址和长度。 但是指针只存储地址,长度则取决于指针的类型&#xff0c;编译器根据指针的类型从指针指向的地址向后寻址&#xff0c; 指针类型不同则寻址范围也不同&#xff0c;比如: int*从指定地址向后寻找4字节作为变量的存储单元&…

首次揭秘!大麦如何应对超大规模高性能选座抢票?

作者| 阿里文娱技术专家恒磊、高级开发工程师新钱出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;背景介绍随着现场娱乐行业的不断发展&#xff0c;各类演出层出不穷&#xff0c;越来越多的演出开启选座购票满足用 户的自主选座需求。大麦的选座不仅面向中小场馆类的…

华为交换机密码恢复

华为交换机密码恢复说明&#xff1a;以下方法将删除原有config文件&#xff0c;使设备恢复到出厂配置。在设备重启时按CtrlB进入BOOT MENU之后&#xff0c;Press Ctrl-B to enter Boot Menu... 5Password : 缺省为空&#xff0c;回车即可1. Download application file to flash…

nginx源码分析--内存对齐处理

1.nginx内存对齐主要是做2件事情&#xff1a; 1) 内存池的内存地址对齐&#xff1b; 2) 长度按照2的幂取整.因为前面结构体已经是对齐了&#xff0c;如果后面的内存池每一小块不是2的幂&#xff0c;那么后面的就不能对齐 2.通用内存对齐理论 内存对齐&#xff1a;数据项只能…

七喜携手AMD,摆脱英特尔“潜规则”

七喜携手AMD&#xff0c;摆脱英特尔“潜规则”<?xml:namespace prefix o ns "urn:schemas-microsoft-com:office:office" />最近&#xff0c;在PC市场随着七喜董事副总裁毛骏飙揭发英特尔制定的潜规则&#xff0c;“游戏规则都是英特尔制定的&#xff0c;全…

半小时训练亿级规模知识图谱,亚马逊AI开源知识图谱嵌入表示框架DGL-KE

出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09; 知识图谱 &#xff08;Knowledge Graph&#xff09;作为一个重要的技术&#xff0c;在近几年里被广泛运用在了信息检索&#xff0c;自然语言处理&#xff0c;以及推荐系统等各种领域。学习知识图谱的嵌入表示 &#x…

数组的各类排序

1 package sort;2 3 /**4 * 数组的各种排序操作5 * Created by liuwei on 16/3/6.6 */7 public class MSort {8 9 /**10 * 直接插入排序11 * 外层一个循环,从第2个元素开始(下标为1),遍历后面的所有元素12 * 内层一个循环,从当前位置position i 开始,每次…

Virtualbox安装使用注意

1.VirtualBox升级到4.3以后不能打开 提示创建 COM 对象失败 应用程序将被中断 解决方案&#xff1a;右键VirtualBox的桌面快捷方式&#xff0c;选择属性&#xff0c;选到兼容性选项卡&#xff0c;勾选“以兼容模式运行这个程序”&#xff0c;下拉框选择Windows Server 2008 …

机器学习项目模板:ML项目的6个基本步骤

来源 | DeepHub IMBA每个机器学习项目都有自己独特的形式。对于每个项目&#xff0c;都可以遵循一组预定义的步骤。尽管没有严格的流程&#xff0c;但是可以提出一个通用模板。准备问题不仅是机器学习&#xff0c;任何项目的第一步都是简单地定义当前的问题。您首先需要了解背景…

ib_logfile 在数据库中有何作用?

ib_logfile 在数据库中有何作用&#xff1f; ib_logfile0/ib_logfile1 文件在数据库中起什么作用&#xff1f; 如果被删除&#xff0c;对数据库有何影响&#xff1f; ----->>>>>>>>>>> 回复 #1 mugua_xinli 的帖子 用于存放InnoDB引擎的事…

Podfile 常见语法

source URL &#xff1a; 指定镜像仓库的源 platform : ios, 6.0 &#xff1a; 指定所支持系统和最低版本 inhibit_all_warnings! &#xff1a;屏蔽所有warning workspace 项目空间名&#xff1a; 指定项目空间名 xcodeproj 工程文件名&#xff1a;指定xcodeproj工程文件名 …

今天学完了ccna

通过10天的学习&#xff0c;终于学完了NA&#xff0c;但是会不会呢&#xff1f;还是个未知数&#xff0c;再就也一知半解的。觉得基础知识太差了&#xff0c;可是看书&#xff0c;又觉得太长了&#xff0c;太多了&#xff0c;晚上老是停电 白天啥也看不进去。热。还是静不下心&…

攀登数据科学家和数据工程师之间的隔墙

来源 | 数据派 THU机器学习的教育和研究重点往往集中在数据科学过程的模型构建、训练、测试和优化等方面。要使这些模型投入使用&#xff0c;需要一套工程专长和组织结构&#xff0c;对于其中的标准尚不存在。有一个架构可以指导数据科学和工程团队相互协作&#xff0c;从而将机…

js变量以及其作用域详解

2019独角兽企业重金招聘Python工程师标准>>> 一、变量的类型 Javascript和Java、C这些语言不同&#xff0c;它是一种无类型、弱检测的语言。它对变量的定义并不需要声明变量类型&#xff0c;我们只要通过赋值的形式&#xff0c;可以将各种类型的数据赋值给同一个变…

在A*寻路中使用二叉堆

在A*寻路中使用二叉堆 作者&#xff1a;Patrick Lester&#xff08;2003年4月11日更新&#xff09; 译者&#xff1a;Panic 2005年3月28日 译者序&#xff1a; 这一篇文章&#xff0c;是“A* Pathfinding for Beginners.”&#xff0c;也就是我翻译的另一篇文章A*寻路初探…