分类: LINUX
2011-05-31 18:16:31
转帖 FROM http://www.cnblogs.com/codingmylife/archive/2010/04/18/1714954.html
没调格式,将就看。。
====转贴开始====
C语言中有几个基本输入函数:
//获取字符系列MINGW 4.4.3中FILE结构体源码:
typedef struct _iobufMINGW 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标准中已经加入对内联函数的支持了。
=================分 割 线=================
提到缓冲区,就不得不提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参数有:
setbuf(stream, buf);在:
注: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来动态申请内存。
=================分 割 线=================
下面来看看几种流行的缓冲区清空方法:
由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函数的介绍,可以得知,setbuf(stdin, NULL);是使stdin输入流由默认缓冲区转为无缓冲区。都没有缓冲区了,当然缓冲区数据残留问题会解决。但这并不是我们想要的。
这里用到了scanf格式化符中的“*”,即赋值屏蔽;“%[^集合]”,匹配不在集合中的任意字符序列。这也带来个问题,缓冲区中的换行符’\n’会留下来,需要额外操作来单独丢弃换行符。