scanf()导致死循环且fflush(stdin)无效详解
2015-09-15 15:51
288 查看
版权归博主所有,转载请注明出处
scanf(const char *format, ......):根据参数format字符串格来格式化标准输入数据到指定内存,format具体使用方法可以参考printf().
注意点:
1、多个参数时,不同参数间可以用空格隔开,也可以用回车隔开,但是只有回车表示结束。
2、当输入参数与格式不对时,函数内部会自动调到下一个输入数据,并比对对应数据是否与格式匹配,不匹配则又调到下一个输入数据,直到匹配或者没有数据,scanf返回值即为匹配成功了的数据个,通过返回值即可判断用户输入是否正常。
3、匹配时跳过的数据不会被系统清空,会依然保留在缓存区,所以此时可能会出现如下情况:
a、没有输入完所有参数,scanf就返回了;
b、scanf一直返回,没有等待用户重新输入,即可能出现死循环。
4、解决 出现第3种情况的办法:
a、使用getchar函数将缓存区里面的数据全部读出,这个方法需确切知道用户输入了多少无效的数据,可用性不强;
b、使用fgets()函数替代getchar(),可以一次性刷新错误缓存数据,保证用户第二次输入重新按干净的环境开始,可用性超强;
b、使用fflush()函数清除缓存:使用ffulsh()时,请不要使用fflush(stdin),因为fflush(stdin)移植性不好,有的平台在会无效,且这个行为是不确定的。
也许有人会说:“居然这样,那么在 scanf 函数后面加上‘fflush(stdin);’,把输入缓冲清空掉不就行了?”然而这是错的!C和C++的标准里从来没有定义过 fflush(stdin)。也许有人会说:“可是我用 fflush(stdin) 解决了这个问题,你怎么能说是错的呢?”的确,某些编译器(如VC6)支持用 fflush(stdin) 来清空输入缓冲,但是并非所有编译器都要支持这个功能(gcc3.2不支持),因为标准中根本没有定义 fflush(stdin)。MSDN 文档里也清楚地写着fflush
on input stream is anextension to the C standard(fflush 操作输入流是对 C 标准的扩充)。当然,如果你毫不在乎程序的移植性,用
fflush(stdin) 也没什么大问题。以下是 C99 对 fflush 函数的定义:
int fflush(FILE<
dbbc
/span> *stream);
如果stream指向输出流或者更新流(update
stream),并且这个更新流
最近执行的操作不是输入,那么fflush函数将把任何未被写入的数据写入stream
指向的文件(如标准输出文件stdout)。否则,fflush函数的行为是不确定的。
fflush(NULL)清空所有输出流和上面提到的更新流。如果发生写错误,fflush
函数会给那些流打上错误标记,并且返回EOF,否则返回0。
由此可知,如果 stream 指向输入流(如 stdin),那么 fflush 函数的行为是不确定的。故而使用
fflush(stdin) 是不正确的,至少是移植性不好的。
SampleCode:
#include <stdio.h>
#include <string.h>
#include <signal.h>
char main_qiut = 0;
void SignalHandlerSetQuit(int sig)
{
printf("Recv signal is %d\n", sig);
signal(SIGSEGV, SIG_DFL);
main_quit = 1;
printf("Please input any key and Enter to exit......\n");
}
int main(int argc, char *argv[])
{
singal(SIGINT, SignalHandlerSetQuit);
singal(SIGBUS, SignalHandlerSetQuit);
singal(SIGTERM, SignalHandlerSetQuit);
singal(SIGSEGV, SignalHandlerSetQuit);
singal(SIGILL, SignalHandlerSetQuit);
singal(SIGPIPE, SIG_IGN);
int x = 0, y = 0,z = 0, ret = 0;
char err_input[128] = "";
for(;;)
{
printf("Please Three number......");
ret = scanf("%d%d%d",&x, &y, &z);
if(1 == main_quit)
{
return 0;
}
if(3 != ret)
{
printf("err key is %s\n", fgets(err_input, sizeof(err_input) - 1), stdin);
continue;
//break;
}
printf("x=%d y=%d z=%d", x, y, z);
}
return 1;
}
步步为营,稳扎稳打
scanf(const char *format, ......):根据参数format字符串格来格式化标准输入数据到指定内存,format具体使用方法可以参考printf().
注意点:
1、多个参数时,不同参数间可以用空格隔开,也可以用回车隔开,但是只有回车表示结束。
2、当输入参数与格式不对时,函数内部会自动调到下一个输入数据,并比对对应数据是否与格式匹配,不匹配则又调到下一个输入数据,直到匹配或者没有数据,scanf返回值即为匹配成功了的数据个,通过返回值即可判断用户输入是否正常。
3、匹配时跳过的数据不会被系统清空,会依然保留在缓存区,所以此时可能会出现如下情况:
a、没有输入完所有参数,scanf就返回了;
b、scanf一直返回,没有等待用户重新输入,即可能出现死循环。
4、解决 出现第3种情况的办法:
a、使用getchar函数将缓存区里面的数据全部读出,这个方法需确切知道用户输入了多少无效的数据,可用性不强;
b、使用fgets()函数替代getchar(),可以一次性刷新错误缓存数据,保证用户第二次输入重新按干净的环境开始,可用性超强;
b、使用fflush()函数清除缓存:使用ffulsh()时,请不要使用fflush(stdin),因为fflush(stdin)移植性不好,有的平台在会无效,且这个行为是不确定的。
也许有人会说:“居然这样,那么在 scanf 函数后面加上‘fflush(stdin);’,把输入缓冲清空掉不就行了?”然而这是错的!C和C++的标准里从来没有定义过 fflush(stdin)。也许有人会说:“可是我用 fflush(stdin) 解决了这个问题,你怎么能说是错的呢?”的确,某些编译器(如VC6)支持用 fflush(stdin) 来清空输入缓冲,但是并非所有编译器都要支持这个功能(gcc3.2不支持),因为标准中根本没有定义 fflush(stdin)。MSDN 文档里也清楚地写着fflush
on input stream is anextension to the C standard(fflush 操作输入流是对 C 标准的扩充)。当然,如果你毫不在乎程序的移植性,用
fflush(stdin) 也没什么大问题。以下是 C99 对 fflush 函数的定义:
int fflush(FILE<
dbbc
/span> *stream);
如果stream指向输出流或者更新流(update
stream),并且这个更新流
最近执行的操作不是输入,那么fflush函数将把任何未被写入的数据写入stream
指向的文件(如标准输出文件stdout)。否则,fflush函数的行为是不确定的。
fflush(NULL)清空所有输出流和上面提到的更新流。如果发生写错误,fflush
函数会给那些流打上错误标记,并且返回EOF,否则返回0。
由此可知,如果 stream 指向输入流(如 stdin),那么 fflush 函数的行为是不确定的。故而使用
fflush(stdin) 是不正确的,至少是移植性不好的。
SampleCode:
#include <stdio.h>
#include <string.h>
#include <signal.h>
char main_qiut = 0;
void SignalHandlerSetQuit(int sig)
{
printf("Recv signal is %d\n", sig);
signal(SIGSEGV, SIG_DFL);
main_quit = 1;
printf("Please input any key and Enter to exit......\n");
}
int main(int argc, char *argv[])
{
singal(SIGINT, SignalHandlerSetQuit);
singal(SIGBUS, SignalHandlerSetQuit);
singal(SIGTERM, SignalHandlerSetQuit);
singal(SIGSEGV, SignalHandlerSetQuit);
singal(SIGILL, SignalHandlerSetQuit);
singal(SIGPIPE, SIG_IGN);
int x = 0, y = 0,z = 0, ret = 0;
char err_input[128] = "";
for(;;)
{
printf("Please Three number......");
ret = scanf("%d%d%d",&x, &y, &z);
if(1 == main_quit)
{
return 0;
}
if(3 != ret)
{
printf("err key is %s\n", fgets(err_input, sizeof(err_input) - 1), stdin);
continue;
//break;
}
printf("x=%d y=%d z=%d", x, y, z);
}
return 1;
}
步步为营,稳扎稳打
相关文章推荐
- Android 压缩解压zip文件
- 结构体struct的sizeof
- MFC的窗口create的时候指定父窗口,获取rect的时候却以桌面为坐标系
- sqrt和Hailstone
- Apache虚拟目录的配置问题
- 《深入理解计算机系统》思考1---系统调用相关
- Eclipse中配置Tomcat
- 中国教育还有英国教育
- hduoj As Easy As A+B 题目1040
- hdu 5444 Elven Postman
- 在c++项目中对于stl的使用检验
- C/C++小程序学习:n*n魔方矩阵实现每行、每列、每一对角线上的元素之和相等
- 充电宝行业洗牌加速
- (整理篇二)Android—流量监控
- 学习笔记(一):offset
- Python builtins
- [zz] ROC曲线
- sql语句总结
- APK类似静默安装的方法
- 初次接触软件测试