如题,朋友领导的孩子大学作业是个C语言编写的管理信息系统发来要我给改改,原代码的配置环境是Windows的C环境,由于10多年没有搞过Windows下的C语言了于是换上了Ubuntu18.04的系统上,本以为都是C语言的标准函数在哪个系统上区别不大,不过正是这个想法要自己调到了坑里,其中最大的一个坑就是scanf的输入问题,代码如下:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. void clean_stdin(void)
  5. {
  6. int c;
  7. do {
  8. c = getchar();
  9. } while (c != '\n' && c != EOF);
  10. }
  11.  
  12. /* return 1 means yes, return 0 means no */
  13. int check_input(char content [])
  14. {
  15. char c[5];
  16.  
  17. fflush(stdin);
  18. int r = scanf("%s",&c);
  19. /*
  20. int r = scanf("%d %d", &c1, &c2);
  21. 如果数据类型不匹配就会输入失败 !!! %d整型数据输入了字符型%c
  22. r=0表示全部没有输入成功, r=1表示成功输入1个数值, r=2表示成功输入2个数值
  23. */
  24. c[4] = '\0';
  25.  
  26. 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)))
  27. {
  28. // printf("输入有误,请重新输入!!!\n若是请回复Y/y/yes,若退出程序请回复N/n/no\n");
  29. printf("%s", content);
  30.  
  31. if(r==0) // linux系统中scanf数据类型匹配错误情况下fflush(stdin)无效
  32. clean_stdin();
  33.  
  34. fflush(stdin);
  35. r = scanf("%s",&c);
  36. }
  37.  
  38. if(strcmp(c, "Y")==0||strcmp(c, "y")==0||strcmp(c, "yes")==0)
  39. {
  40. return 1;
  41. }
  42. return 0;
  43. }
  44.  
  45. int main()
  46. {
  47. char content[] = "输入有误,请重新输入!!!\n确认操作请输入Y/y/yes,退回主菜单请输入N/n/no\n";
  48.  
  49. printf("确认操作请输入Y/y/yes,退回主菜单请输入N/n/no\n");
  50.  
  51. int res = check_input(content);
  52. if(res==0) // return 1 means yes, return 0 means no
  53. {
  54. printf("退回操作!!!\n");
  55. }
  56. else
  57. {
  58. printf("继续操作!!!\n");
  59. }
  60.  
  61. }

这个代码本身也刷新了我很多的知识点,以前都没有想过 scanf 这个函数还有返回值,毕竟当年用的时候也是在上大学本科的时候,而且这个返回值还挺有用。

(毕竟上学时候重来不会考虑输入检测这事情)

  1. /*
  2. int r = scanf("%d %d", &c1, &c2);
  3. 如果数据类型不匹配就会输入失败 !!! %d整型数据输入了字符型%c
  4. r=0表示全部没有输入成功, r=1表示成功输入1个数值, r=2表示成功输入2个数值
  5. */

==============================================

需要注意的是如果scanf中是字符输入是永远不会出现类型匹配错误的,因为所有输入都可以看做是字符输入,如:

scanf("%c", &c );

scanf("%s", &c );

会出现scanf匹配错误的是这种:

scanf("%d", &c );

在Windows系统下 scanf 因为类型不匹配是不太会引起太多问题的,即使出现问题使用fflush(stdin)然后一个循环输入就解决了,而在linux系统下发现这个是不好用的。

在linux中如果 scanf 输入类型不匹配这时fflush(stdin)是不起作用的,输入缓冲中的值会一直存在的(不清空),然后就会造成死循环然后一直循环输入。

例子:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. void clean_stdin(void)
  5. {
  6. int c;
  7. do {
  8. c = getchar();
  9. } while (c != '\n' && c != EOF);
  10. }
  11.  
  12. /* return 1 means yes, return 0 means no */
  13. int check_input(char content [])
  14. {
  15. int c;
  16.  
  17. fflush(stdin);
  18. int r = scanf("%d",&c);
  19. /*
  20. int r = scanf("%d %d", &c1, &c2);
  21. 如果数据类型不匹配就会输入失败 !!! %d整型数据输入了字符型%c
  22. r=0表示全部没有输入成功, r=1表示成功输入1个数值, r=2表示成功输入2个数值
  23. */
  24.  
  25. while(!(r==1&&(c==1||c==2)))
  26. {
  27. printf("%s", content);
  28.  
  29. // if(r==0) // linux系统中scanf数据类型匹配错误情况下fflush(stdin)无效
  30. // clean_stdin();
  31.  
  32. fflush(stdin);
  33. r = scanf("%d",&c);
  34. }
  35.  
  36. if(c==1)
  37. {
  38. return 1;
  39. }
  40. return 0;
  41. }
  42.  
  43. int main()
  44. {
  45. char content[] = "输入有误,请重新输入!!!\n确认操作请输入 1,退回主菜单请输入 2\n";
  46.  
  47. printf("确认操作请输入 1,退回主菜单请输入 2\n");
  48.  
  49. int res = check_input(content);
  50. if(res==0) // return 1 means yes, return 0 means no
  51. {
  52. printf("退回操作!!!\n");
  53. }
  54. else
  55. {
  56. printf("继续操作!!!\n");
  57. }
  58.  
  59. }

该代码运行时如果输入字符,如“a”回车后就会死循环:

同时使用 fflush(stdin)和getchar()的使用:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. void clean_stdin(void)
  5. {
  6. int c;
  7. do {
  8. c = getchar();
  9. } while (c != '\n' && c != EOF);
  10. }
  11.  
  12. /* return 1 means yes, return 0 means no */
  13. int check_input(char content [])
  14. {
  15. int c;
  16.  
  17. fflush(stdin);
  18. int r = scanf("%d",&c);
  19. /*
  20. int r = scanf("%d %d", &c1, &c2);
  21. 如果数据类型不匹配就会输入失败 !!! %d整型数据输入了字符型%c
  22. r=0表示全部没有输入成功, r=1表示成功输入1个数值, r=2表示成功输入2个数值
  23. */
  24.  
  25. while(!(r==1&&(c==1||c==2)))
  26. {
  27. printf("%s", content);
  28.  
  29. if(r==0) // linux系统中scanf数据类型匹配错误情况下fflush(stdin)无效
  30. clean_stdin();
  31.  
  32. fflush(stdin);
  33. r = scanf("%d",&c);
  34. }
  35.  
  36. if(c==1)
  37. {
  38. return 1;
  39. }
  40. return 0;
  41. }
  42.  
  43. int main()
  44. {
  45. char content[] = "输入有误,请重新输入!!!\n确认操作请输入 1,退回主菜单请输入 2\n";
  46.  
  47. printf("确认操作请输入 1,退回主菜单请输入 2\n");
  48.  
  49. int res = check_input(content);
  50. if(res==0) // return 1 means yes, return 0 means no
  51. {
  52. printf("退回操作!!!\n");
  53. }
  54. else
  55. {
  56. printf("继续操作!!!\n");
  57. }
  58.  
  59. }

重要部分代码:

  1. if(r==0) // linux系统中scanf数据类型匹配错误情况下fflush(stdin)无效
  2. clean_stdin();

需要注意的是只有在scanf匹配错误的时候才好使用getchar函数,否则多需要输入一次回车才可以,因为getchar是阻塞操作如果缓冲区空间中没有结束符会一直等待输入。

更稳妥的方式可以写为:

  1. if(r==0) // linux系统中scanf数据类型匹配错误情况下fflush(stdin)无效
  2. clean_stdin();
  3. else
  4. fflush(stdin);

整体代码:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. void clean_stdin(void)
  5. {
  6. int c;
  7. do {
  8. c = getchar();
  9. } while (c != '\n' && c != EOF);
  10. }
  11.  
  12. /* return 1 means yes, return 0 means no */
  13. int check_input(char content [])
  14. {
  15. int c;
  16.  
  17. fflush(stdin);
  18. int r = scanf("%d",&c);
  19. /*
  20. int r = scanf("%d %d", &c1, &c2);
  21. 如果数据类型不匹配就会输入失败 !!! %d整型数据输入了字符型%c
  22. r=0表示全部没有输入成功, r=1表示成功输入1个数值, r=2表示成功输入2个数值
  23. */
  24.  
  25. while(!(r==1&&(c==1||c==2)))
  26. {
  27. printf("%s", content);
  28.  
  29. if(r==0) // linux系统中scanf数据类型匹配错误情况下fflush(stdin)无效
  30. clean_stdin();
  31. else
  32. fflush(stdin);
  33.  
  34. r = scanf("%d",&c);
  35. }
  36.  
  37. if(c==1)
  38. {
  39. return 1;
  40. }
  41. return 0;
  42. }
  43.  
  44. int main()
  45. {
  46. char content[] = "输入有误,请重新输入!!!\n确认操作请输入 1,退回主菜单请输入 2\n";
  47.  
  48. printf("确认操作请输入 1,退回主菜单请输入 2\n");
  49.  
  50. int res = check_input(content);
  51. if(res==0) // return 1 means yes, return 0 means no
  52. {
  53. printf("退回操作!!!\n");
  54. }
  55. else
  56. {
  57. printf("继续操作!!!\n");
  58. }
  59.  
  60. }

==========================================

引用: 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()的使用的更多相关文章

  1. sqlserver text类型字段错误 net.sourceforge.jtds.jdbc.ClobImpl@66fa192的解决方法

    1. SqlServer数据库中text/ntext字段,在用jtds1.2驱动时,会出现用getString()取不到值的问题,toString()也不行. 昨天查了下帮助可以通过简单的配置解决.即 ...

  2. Win7系统中提示:本地无法启动MySQL服务,报的错误:1067,进程意外终止的解决方法。

    Win7系统中提示:本地无法启动MySQL服务,报的错误:1067,进程意外终止的解决方法. 在本地计算机无法启动MYSQL服务错误1067进程意外终止.这种情况一般是my.ini文件配置出错了1.首 ...

  3. 关于错误Access Violation和too many consecutive exceptions 解决方法

    关于错误Access Violation和too many consecutive exceptions 解决方法 “如果DLL中用到了DELPHI的string类型,则DLL和主程序中都需要加上Sh ...

  4. 在Eclipse中运行Jboss时出现java.lang.OutOfMemoryError:PermGen space及其解决方法

    在Eclipse中运行Jboss时出现java.lang.OutOfMemoryError:PermGen space及其解决方法 在Eclipse中运行Jboss时,时间太长可能有时候会出现java ...

  5. 错误Name node is in safe mode的解决方法 (转)

    原文链接:错误Name node is in safe mode的解决方法 将本地文件拷贝到hdfs上去,结果上错误:Name node is in safe mode 这是因为在分布式文件系统启动的 ...

  6. ckfinder在IE10,IE9中的弹出框不能选择,或者不能上传解决方法

    在IE9,或IE10中ckfinder在IE10,IE9中的弹出框不能选择,或者不能上传解决方法   把弹出框嵌入到jquery dialog中.可以解决 I did: // javascript f ...

  7. linux中/etc/fstab文件删除或修改了,导致系统无法启动

    在linux中,/etc/fstab文件是磁盘挂载的问题,若该文件不小心给修改了,或者被删除了,那么就会导致系统无法重启.因为/etc/fstab文件是记录磁盘挂载的信息,若该文件出现了问题,那么对应 ...

  8. Emacs中编辑保存makefile文件时会错误地将TAB转成空格的解决方法

    问题描述 我的Emacs使用了Purcell的配置,在其配置中使用了whitespace-cleanup,且通过在.emacs.d/lisp/init-edit-utils.el中设定: (requi ...

  9. MVC中提示错误:从客户端中检测到有潜在危险的 Request.Form 值的详细解决方法

    今天往MVC中加入了一个富文本编辑框,在提交信息的时候报了如下的错误:从客户端(Content="<EM ><STRONG ><U >这是测试这...&q ...

  10. Linux网卡聚合时,其中一个网卡有两种配置的解决方法

    先来看看: ficonfig 其中第一网卡是ssh使用: 第二个网卡是在Linux 最小化安装后IP的配置(手动获取静态IP地址)这个文章中配置过ip是192.168.1.2:在Linux重命名网卡名 ...

随机推荐

  1. Oracle使用序列和触发器设置自增字段

    一.创建一张工作表 例: create table tv(ID NUMBER primary key,TVNAME VARCHAR(16),ISPASS NUMBER);   二.先创建一个序列 cr ...

  2. JVM性能分析与故障排查

    引言 JVM调优 程序在上线前的测试或运行中有时会出现一些大大小小的JVM问题,比如cpu load过高.请求延迟.tps降低等,甚至出现内存泄漏(每次垃圾收集使用的时间越来越长,垃圾收集频率越来越高 ...

  3. 3个月搞定计算机二级C语言!高效刷题系列进行中

    前言 大家好,我是梁国庆. 计算机二级应该是每一位大学生的必修课,相信很多同学的大学flag中都会有它的身影. 我在大学里也不止一次的想要考计算机二级office,但由于种种原因,备考了几次都不了了之 ...

  4. python pika rabbitmq demo

    import pika import json # https://www.cnblogs.com/zhaohuaxishi/p/12107392.html # https://www.cnblogs ...

  5. GIS数据获取:气象数据免费下载网站

      本文对目前主要的气象数据获取网站加以整理与介绍.   本文为"GIS数据获取整理"专栏中第二篇独立博客,因此本文全部标题均由"2"开头.本文对目前主要的气象 ...

  6. Oracle 数据库 命令行安装

    Oracle 数据库 命令行安装 1. 准备工作 关闭 防火墙,关闭 SElinux 2. 安装相关依赖包 yum -y install binutils compat-libcap1 compat- ...

  7. 在Linux驱动中使用input子系统

    在Linux驱动中使用输入子系统 参考: https://www.cnblogs.com/lifexy/p/7553861.html https://www.cnblogs.com/linux-37g ...

  8. 多个子节点收集日志-主节点上传到HDFS

    Master: ---------------------- #MasterAgentMasterAgent.channels = c1MasterAgent.sources = s1MasterAg ...

  9. 详解Web应用安全系列(9)点击劫持

    点击劫持(Clickjacking)漏洞,也被称为界面伪装攻击(UI Redress Attack)或UI覆盖攻击,是一种利用视觉欺骗手段进行的网络攻击方式.这种攻击方式通过技术手段欺骗用户点击他们本 ...

  10. SpirngBoot整合MybatisPlus 附源码

    项目搭建 目录结构 pom.xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns ...