C语言刷新缓冲区(转载)
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。
=================分 割 线=================
提到缓冲区,就不得不提setbuf和setvbuf两个缓冲区设置函数,其声明如下:
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语言刷新缓冲区(转载)的更多相关文章
- C语言 刷新缓冲区
fflush int fflush(FILE* stream); 用于清空文件缓冲区,如果文件是以写的方式打开 的,则把缓冲区内容写入文件. eg: 1. #include <stdio.h&g ...
- C语言:缓冲区
缓冲区(Buffer)又称为缓存(Cache),是内存空间的一部分.也就是说,计算机在内存中预留了一定的存储空间,用来暂时保存输入或输出的数据,这部分预留的空间就叫做缓冲区(缓存).有时候,从键盘输入 ...
- 【C++】cout未刷新缓冲区仍会输出的问题
众所周知,cout是一个流对象,管理一个缓冲区.当使用<<操作符输出字符串时,字符串不是直接被输出到屏幕上,而是首先被插入到该流的缓存(buffer)中.而只有当缓冲区被刷新时,字符串才会 ...
- 【Python】【demo实验1】【Python运行时强制刷新缓冲区,输出信息】(Python3 应不存在类似情况)
[原文] 需求:打印一颗 ”*” 休息1s 代码如下: #!/usr/bin/python #coding=utf-8 ''' 暂停1s输出 ''' import time def printStar ...
- bp神经网络模型推导与c语言实现(转载)
转载出处:http://www.cnblogs.com/jzhlin/archive/2012/07/28/bp.html BP 神经网络中的 BP 为 Back Propagation 的简写,最 ...
- c语言指针疑惑[转载]
c99的动态数组是在栈上面开辟的,而new出来的是在堆上面开辟的.栈和堆的地址是从两端相向增长的.栈很小,一般只有几十k,vc6好像是64k.堆很大,在win32的虚拟地址空间可以分配到2g的内存.栈 ...
- C语言基础(转载自大海笔记)
# C语言基础2015年03月26日10:04:411. 语言排行榜C——java——objective-C2. 进制:进制:进位机制.用普通的话讲,应该为人为的定义一种度量来标识一样东西 ...
- c语言命名规则 [转载]
C语言变量名命名规则 一.程序风格: 1.严格采用阶梯层次组织程序代码: 各层次缩进的分格采用VC的缺省风格,即每层次缩进为4格,括号位于下一行. 要求相匹配的 ...
- C语言函数指针(转载)
二.通常的函数调用 一个通常的函数调用的例子:/* 自行包含头文件 */void MyFun(int x); /* 此处的声明也可写成:void MyFun(int) */int main(int a ...
随机推荐
- 【转】设置TextView文字居中
原文网址:http://blog.csdn.net/lanpy88/article/details/6616924 有2种方法可以设置TextView文字居中: 一:在xml文件设置:android: ...
- win7 清理系统
1. 先用CCleaner等第三方软件清理一下.2. 将用户文件.我的文档.我的音乐.我的视频.桌面等路径更改到非系统分区(文件也会一并移动过去)3. 将系统盘的系统还原占用空间比减小,将大部分虚拟内 ...
- C#编译时出现“不安全代码只会在使用 /unsafe 编译的情况下出现”错误的解决
原因是:在编译的代码里面有不安全类型unsafe方法或类!解决方法:将项目属性页中生成下的“允许不安全代码”复选框打上对勾即可,方法如下:项目属性对话框->生成->允许不安全代码块 选中即 ...
- InstallShield: cannot extract icon with index 0错误解决方案
在VS2012打包过程中,遇到这个错误,困扰我好几天,后来通过谷歌找到解决方案,如下: Expand the deploy solution (+) on the right panel (Solut ...
- HDOJ 2092 整数解(2次方程整数解公式)
Problem Description 有二个整数,它们加起来等于某个整数,乘起来又等于另一个整数,它们到底是真还是假,也就是这种整数到底存不存在,实在有点吃不准,你能快速回答吗?看来只能通过编程. ...
- Visual Studio创建跨平台移动应用_01.Cordova&Xamarin
目前开发移动应用有三种模式:Native.Hybird.Web,若要开发跨平台的移动应用,又希望与本地API交互,那么Hybird是一个非常好的选择. 作为一个.Net程序员, ...
- 如何编写一个JSON解析器
编写一个JSON解析器实际上就是一个函数,它的输入是一个表示JSON的字符串,输出是结构化的对应到语言本身的数据结构. 和XML相比,JSON本身结构非常简单,并且仅有几种数据类型,以Java为例,对 ...
- POJ 1458-Common Subsequence(线性dp/LCS)
Common Subsequence Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 39009 Accepted: 15 ...
- C语言单元測试
C语言单元測试 对于敏捷开发来说,单元測试不可缺少,对于Java开发来说,JUnit非常好,对于C++开发,也有CPPUnit可供使用,而对于传统的C语言开发,就没有非常好的工具可供使用,能够找到的有 ...
- 【转】IOS7 MPMoviePlayerViewController横屏显示
在应用程序中用到MPMoviePlayerViewController时,有时需要保持应用程序为竖屏状态,而视频播放器显示为横屏,如何做呢?如果采用强制横屏的方法,应用审核的时候是不会通过的,因为该方 ...