java 清除stdin缓冲区,怎么较为完善地清空输入缓冲区

怎样较为完善地清空输入缓冲区

一个简单的测试程序对比得出清除缓冲区作用:

未加清除缓冲功能的测试程序:#include

void CreateFile(void)

{}

void OpenFile(void)

{}

void SaveFile(void)

{}

void CmdRunning()

{

int iCmdNum = 0;

void (*pCmd)() = NULL;

do

{

pCmd = NULL;

printf("请选择:0. 退出;1. 新建文件;2. 打开文件;3. 保存文件\n");

iCmdNum = getchar();//此时输入的是字符

//fflush(stdin);//清空缓冲区

switch(iCmdNum)

{

case '0':printf("谢谢使用,再见!\n");

break;

case '1':pCmd = CreateFile;

break;

case '2':pCmd = OpenFile;

break;

case '3':pCmd = SaveFile;

break;

default:printf("对不起,你选择的数字不存在,请重新选择!\n");

}

if(NULL!=pCmd)

{

pCmd(); // 与(*pCmd)();等价 (*pCmd)()

}

}while('0'!=iCmdNum);

}

int main(void)

{

CmdRunning();

return 0;

}

实验结果:

103427207.png

加上清除缓冲功能以后:

#include

void CreateFile(void)

{}

void OpenFile(void)

{}

void SaveFile(void)

{}

void CmdRunning()

{

int iCmdNum = 0;

void (*pCmd)() = NULL;

do

{

pCmd = NULL;

printf("请选择:0. 退出;1. 新建文件;2. 打开文件;3. 保存文件\n");

iCmdNum = getchar();//此时输入的是字符

fflush(stdin);//清空缓冲区

switch(iCmdNum)

{

case '0':printf("谢谢使用,再见!\n");

break;

case '1':pCmd = CreateFile;

break;

case '2':pCmd = OpenFile;

break;

case '3':pCmd = SaveFile;

break;

default:printf("对不起,你选择的数字不存在,请重新选择!\n");

}

if(NULL!=pCmd)

{

pCmd(); // 与(*pCmd)();等价 (*pCmd)()

}

}while('0'!=iCmdNum);

}

int main(void)

{

CmdRunning();

return 0;

}

103427208.png

清除缓冲区,这里缓冲区有我们实验输入时不小心或者是不得不产生的回车符影响,fflush(stdin);把回车符从缓冲区中清除掉。

清除缓冲区的几个方法:

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值。

_CRTIMP int __cdecl getchar(void);

清除方法:

(1)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函数会导致任何的由于流被传入到宿主环境(宿主环境可以理解为操作系统或内核)的不成文数据(待写数据)被写入文件当中,否则,这种行为是未定义的。

由上面可知对于fflush输入流为参数的行为是未定义的。(所以如果 stream 指向输入流(如 stdin),那么 fflush 函数的行为是不确定的。故而使用fflush(stdin)是不正确的。

)

但是在VC的MSDN中写到:

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向该文件写入相关流。如果是为了输入而打开,则fflush清空缓冲区内容。

由此可知fflush(stdin)为清空输入缓冲区是有作用的。

(2)

setbuf (stdin,NULL);

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

(3)

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

(4)最佳方案:

int c;

while((c=getchar()) != '\n' && c!=EOF);

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

合理的结论:

由以上分析可知,在C语言中清空输入缓冲区的最佳方法是在一个循环中不断获取输入流中的残留数据并把它”吃掉“来起到清除输入缓冲区的作用。

简单例子:

#include

int main(void)

{

int i,c;

for(;;)

{

fputs("Please input an integer :",stdout);

scanf("%d",&i);

if( feof(stdin) || ferror(stdin) )

{

/* 如果用户输入文件结束标志(或文件已被读完), */

/* 或者发生读写错误,则退出循环 */

break;

}

/* 没有发生错误,清空输入流。 */

/* 通过 while 循环把输入流中的余留数据“吃”掉 */

while((c=getchar())!='\n' && c!=EOF);

printf("%d\n",i);

}

return 0;

}

当输入8并进行单步调试出现以下结果:

103427209.png

103427210.png

输入80

103427211.png

c的值始终为10!!!因为回车符的值为0x0A 嘛~~~~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值