Linux中scanf类型匹配错误,特指scanf("%d", &c ) ,导致死循环的解决方法 —— fflush(stdin)和getchar()的使用
如题,朋友领导的孩子大学作业是个C语言编写的管理信息系统发来要我给改改,原代码的配置环境是Windows的C环境,由于10多年没有搞过Windows下的C语言了于是换上了Ubuntu18.04的系统上,本以为都是C语言的标准函数在哪个系统上区别不大,不过正是这个想法要自己调到了坑里,其中最大的一个坑就是scanf的输入问题,代码如下:
- #include <stdio.h>
- #include <stdlib.h>
- void clean_stdin(void)
- {
- int c;
- do {
- c = getchar();
- } while (c != '\n' && c != EOF);
- }
- /* return 1 means yes, return 0 means no */
- int check_input(char content [])
- {
- char c[5];
- fflush(stdin);
- int r = scanf("%s",&c);
- /*
- int r = scanf("%d %d", &c1, &c2);
- 如果数据类型不匹配就会输入失败 !!! %d整型数据输入了字符型%c
- r=0表示全部没有输入成功, r=1表示成功输入1个数值, r=2表示成功输入2个数值
- */
- c[4] = '\0';
- while(!(r==1&&(strcmp(c, "Y")==0||strcmp(c, "y")==0||strcmp(c, "yes")==0||strcmp(c, "N")==0||strcmp(c, "n")==0||strcmp(c, "no")==0)))
- {
- // printf("输入有误,请重新输入!!!\n若是请回复Y/y/yes,若退出程序请回复N/n/no\n");
- printf("%s", content);
- if(r==0) // linux系统中scanf数据类型匹配错误情况下fflush(stdin)无效
- clean_stdin();
- fflush(stdin);
- r = scanf("%s",&c);
- }
- if(strcmp(c, "Y")==0||strcmp(c, "y")==0||strcmp(c, "yes")==0)
- {
- return 1;
- }
- return 0;
- }
- int main()
- {
- char content[] = "输入有误,请重新输入!!!\n确认操作请输入Y/y/yes,退回主菜单请输入N/n/no\n";
- printf("确认操作请输入Y/y/yes,退回主菜单请输入N/n/no\n");
- int res = check_input(content);
- if(res==0) // return 1 means yes, return 0 means no
- {
- printf("退回操作!!!\n");
- }
- else
- {
- printf("继续操作!!!\n");
- }
- }
这个代码本身也刷新了我很多的知识点,以前都没有想过 scanf 这个函数还有返回值,毕竟当年用的时候也是在上大学本科的时候,而且这个返回值还挺有用。
(毕竟上学时候重来不会考虑输入检测这事情)
- /*
- int r = scanf("%d %d", &c1, &c2);
- 如果数据类型不匹配就会输入失败 !!! %d整型数据输入了字符型%c
- r=0表示全部没有输入成功, r=1表示成功输入1个数值, r=2表示成功输入2个数值
- */
==============================================
需要注意的是如果scanf中是字符输入是永远不会出现类型匹配错误的,因为所有输入都可以看做是字符输入,如:
scanf("%c", &c );
scanf("%s", &c );
会出现scanf匹配错误的是这种:
scanf("%d", &c );
在Windows系统下 scanf 因为类型不匹配是不太会引起太多问题的,即使出现问题使用fflush(stdin)然后一个循环输入就解决了,而在linux系统下发现这个是不好用的。
在linux中如果 scanf 输入类型不匹配这时fflush(stdin)是不起作用的,输入缓冲中的值会一直存在的(不清空),然后就会造成死循环然后一直循环输入。
例子:
- #include <stdio.h>
- #include <stdlib.h>
- void clean_stdin(void)
- {
- int c;
- do {
- c = getchar();
- } while (c != '\n' && c != EOF);
- }
- /* return 1 means yes, return 0 means no */
- int check_input(char content [])
- {
- int c;
- fflush(stdin);
- int r = scanf("%d",&c);
- /*
- int r = scanf("%d %d", &c1, &c2);
- 如果数据类型不匹配就会输入失败 !!! %d整型数据输入了字符型%c
- r=0表示全部没有输入成功, r=1表示成功输入1个数值, r=2表示成功输入2个数值
- */
- while(!(r==1&&(c==1||c==2)))
- {
- printf("%s", content);
- // if(r==0) // linux系统中scanf数据类型匹配错误情况下fflush(stdin)无效
- // clean_stdin();
- fflush(stdin);
- r = scanf("%d",&c);
- }
- if(c==1)
- {
- return 1;
- }
- return 0;
- }
- int main()
- {
- char content[] = "输入有误,请重新输入!!!\n确认操作请输入 1,退回主菜单请输入 2\n";
- printf("确认操作请输入 1,退回主菜单请输入 2\n");
- int res = check_input(content);
- if(res==0) // return 1 means yes, return 0 means no
- {
- printf("退回操作!!!\n");
- }
- else
- {
- printf("继续操作!!!\n");
- }
- }
该代码运行时如果输入字符,如“a”回车后就会死循环:
同时使用 fflush(stdin)和getchar()的使用:
- #include <stdio.h>
- #include <stdlib.h>
- void clean_stdin(void)
- {
- int c;
- do {
- c = getchar();
- } while (c != '\n' && c != EOF);
- }
- /* return 1 means yes, return 0 means no */
- int check_input(char content [])
- {
- int c;
- fflush(stdin);
- int r = scanf("%d",&c);
- /*
- int r = scanf("%d %d", &c1, &c2);
- 如果数据类型不匹配就会输入失败 !!! %d整型数据输入了字符型%c
- r=0表示全部没有输入成功, r=1表示成功输入1个数值, r=2表示成功输入2个数值
- */
- while(!(r==1&&(c==1||c==2)))
- {
- printf("%s", content);
- if(r==0) // linux系统中scanf数据类型匹配错误情况下fflush(stdin)无效
- clean_stdin();
- fflush(stdin);
- r = scanf("%d",&c);
- }
- if(c==1)
- {
- return 1;
- }
- return 0;
- }
- int main()
- {
- char content[] = "输入有误,请重新输入!!!\n确认操作请输入 1,退回主菜单请输入 2\n";
- printf("确认操作请输入 1,退回主菜单请输入 2\n");
- int res = check_input(content);
- if(res==0) // return 1 means yes, return 0 means no
- {
- printf("退回操作!!!\n");
- }
- else
- {
- printf("继续操作!!!\n");
- }
- }
重要部分代码:
- if(r==0) // linux系统中scanf数据类型匹配错误情况下fflush(stdin)无效
- clean_stdin();
需要注意的是只有在scanf匹配错误的时候才好使用getchar函数,否则多需要输入一次回车才可以,因为getchar是阻塞操作如果缓冲区空间中没有结束符会一直等待输入。
更稳妥的方式可以写为:
- if(r==0) // linux系统中scanf数据类型匹配错误情况下fflush(stdin)无效
- clean_stdin();
- else
- fflush(stdin);
整体代码:
- #include <stdio.h>
- #include <stdlib.h>
- void clean_stdin(void)
- {
- int c;
- do {
- c = getchar();
- } while (c != '\n' && c != EOF);
- }
- /* return 1 means yes, return 0 means no */
- int check_input(char content [])
- {
- int c;
- fflush(stdin);
- int r = scanf("%d",&c);
- /*
- int r = scanf("%d %d", &c1, &c2);
- 如果数据类型不匹配就会输入失败 !!! %d整型数据输入了字符型%c
- r=0表示全部没有输入成功, r=1表示成功输入1个数值, r=2表示成功输入2个数值
- */
- while(!(r==1&&(c==1||c==2)))
- {
- printf("%s", content);
- if(r==0) // linux系统中scanf数据类型匹配错误情况下fflush(stdin)无效
- clean_stdin();
- else
- fflush(stdin);
- r = scanf("%d",&c);
- }
- if(c==1)
- {
- return 1;
- }
- return 0;
- }
- int main()
- {
- char content[] = "输入有误,请重新输入!!!\n确认操作请输入 1,退回主菜单请输入 2\n";
- printf("确认操作请输入 1,退回主菜单请输入 2\n");
- int res = check_input(content);
- if(res==0) // return 1 means yes, return 0 means no
- {
- printf("退回操作!!!\n");
- }
- else
- {
- printf("继续操作!!!\n");
- }
- }
==========================================
引用: https://www.shuzhiduo.com/A/E35poObJvX/
在Windows中不匹配的问题:
==========================================
附加说明:
在linux系统中本文所写的函数 clean_stdin 中利用getchar函数对EOF进行判断是无意义的,因为在linux系统中是无法从键盘输入这个字符的。
(具体也不是很理解)
详细见:https://www.codenong.com/9796054/
==========================================
参考:
https://blog.csdn.net/chunqiu_lfq/article/details/21841217
https://blog.csdn.net/weixin_30883777/article/details/97901491
https://www.shuzhiduo.com/A/E35poObJvX/
Linux中scanf类型匹配错误,特指scanf("%d", &c ) ,导致死循环的解决方法 —— fflush(stdin)和getchar()的使用的更多相关文章
- sqlserver text类型字段错误 net.sourceforge.jtds.jdbc.ClobImpl@66fa192的解决方法
1. SqlServer数据库中text/ntext字段,在用jtds1.2驱动时,会出现用getString()取不到值的问题,toString()也不行. 昨天查了下帮助可以通过简单的配置解决.即 ...
- Win7系统中提示:本地无法启动MySQL服务,报的错误:1067,进程意外终止的解决方法。
Win7系统中提示:本地无法启动MySQL服务,报的错误:1067,进程意外终止的解决方法. 在本地计算机无法启动MYSQL服务错误1067进程意外终止.这种情况一般是my.ini文件配置出错了1.首 ...
- 关于错误Access Violation和too many consecutive exceptions 解决方法
关于错误Access Violation和too many consecutive exceptions 解决方法 “如果DLL中用到了DELPHI的string类型,则DLL和主程序中都需要加上Sh ...
- 在Eclipse中运行Jboss时出现java.lang.OutOfMemoryError:PermGen space及其解决方法
在Eclipse中运行Jboss时出现java.lang.OutOfMemoryError:PermGen space及其解决方法 在Eclipse中运行Jboss时,时间太长可能有时候会出现java ...
- 错误Name node is in safe mode的解决方法 (转)
原文链接:错误Name node is in safe mode的解决方法 将本地文件拷贝到hdfs上去,结果上错误:Name node is in safe mode 这是因为在分布式文件系统启动的 ...
- ckfinder在IE10,IE9中的弹出框不能选择,或者不能上传解决方法
在IE9,或IE10中ckfinder在IE10,IE9中的弹出框不能选择,或者不能上传解决方法 把弹出框嵌入到jquery dialog中.可以解决 I did: // javascript f ...
- linux中/etc/fstab文件删除或修改了,导致系统无法启动
在linux中,/etc/fstab文件是磁盘挂载的问题,若该文件不小心给修改了,或者被删除了,那么就会导致系统无法重启.因为/etc/fstab文件是记录磁盘挂载的信息,若该文件出现了问题,那么对应 ...
- Emacs中编辑保存makefile文件时会错误地将TAB转成空格的解决方法
问题描述 我的Emacs使用了Purcell的配置,在其配置中使用了whitespace-cleanup,且通过在.emacs.d/lisp/init-edit-utils.el中设定: (requi ...
- MVC中提示错误:从客户端中检测到有潜在危险的 Request.Form 值的详细解决方法
今天往MVC中加入了一个富文本编辑框,在提交信息的时候报了如下的错误:从客户端(Content="<EM ><STRONG ><U >这是测试这...&q ...
- Linux网卡聚合时,其中一个网卡有两种配置的解决方法
先来看看: ficonfig 其中第一网卡是ssh使用: 第二个网卡是在Linux 最小化安装后IP的配置(手动获取静态IP地址)这个文章中配置过ip是192.168.1.2:在Linux重命名网卡名 ...
随机推荐
- Oracle使用序列和触发器设置自增字段
一.创建一张工作表 例: create table tv(ID NUMBER primary key,TVNAME VARCHAR(16),ISPASS NUMBER); 二.先创建一个序列 cr ...
- JVM性能分析与故障排查
引言 JVM调优 程序在上线前的测试或运行中有时会出现一些大大小小的JVM问题,比如cpu load过高.请求延迟.tps降低等,甚至出现内存泄漏(每次垃圾收集使用的时间越来越长,垃圾收集频率越来越高 ...
- 3个月搞定计算机二级C语言!高效刷题系列进行中
前言 大家好,我是梁国庆. 计算机二级应该是每一位大学生的必修课,相信很多同学的大学flag中都会有它的身影. 我在大学里也不止一次的想要考计算机二级office,但由于种种原因,备考了几次都不了了之 ...
- python pika rabbitmq demo
import pika import json # https://www.cnblogs.com/zhaohuaxishi/p/12107392.html # https://www.cnblogs ...
- GIS数据获取:气象数据免费下载网站
本文对目前主要的气象数据获取网站加以整理与介绍. 本文为"GIS数据获取整理"专栏中第二篇独立博客,因此本文全部标题均由"2"开头.本文对目前主要的气象 ...
- Oracle 数据库 命令行安装
Oracle 数据库 命令行安装 1. 准备工作 关闭 防火墙,关闭 SElinux 2. 安装相关依赖包 yum -y install binutils compat-libcap1 compat- ...
- 在Linux驱动中使用input子系统
在Linux驱动中使用输入子系统 参考: https://www.cnblogs.com/lifexy/p/7553861.html https://www.cnblogs.com/linux-37g ...
- 多个子节点收集日志-主节点上传到HDFS
Master: ---------------------- #MasterAgentMasterAgent.channels = c1MasterAgent.sources = s1MasterAg ...
- 详解Web应用安全系列(9)点击劫持
点击劫持(Clickjacking)漏洞,也被称为界面伪装攻击(UI Redress Attack)或UI覆盖攻击,是一种利用视觉欺骗手段进行的网络攻击方式.这种攻击方式通过技术手段欺骗用户点击他们本 ...
- SpirngBoot整合MybatisPlus 附源码
项目搭建 目录结构 pom.xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns ...