如题,朋友领导的孩子大学作业是个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()的使用的更多相关文章

  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. epoll使用与原理

    使用要点 边缘模式(ET)与水平模式(LT)区别 下面内容来自linux man page The epoll event distribution interface is able to beha ...

  2. SpringBoot3整合SpringDoc实现在线接口文档

    写在前面 在现目前项目开发中,一般都是前后端分离项目.前端小姐姐负责开发前端,苦逼的我们负责后端开发 事实是一个人全干,在这过程中编写接口文档就显得尤为重要了.然而作为一个程序员,最怕的莫过于自己写文 ...

  3. spring boot jpa 进行通用多条件动态查询和更新 接口

    原因: jpa 没有类似于mybatis的那种 拼接sql的方式 想动态更新 需要使用 CriteriaUpdate的方式 去一直拼接,其实大多数场景只要传入一个非空实体类,去动态拼接sql 1.定义 ...

  4. 探索Semantic Kernel内置插件:深入了解HttpPlugin的应用

    前言 上一章我们熟悉了Semantic Kernel中的内置插件和对ConversationSummaryPlugin插件进行了实战,本章我们讲解一下另一个常用的内置插件HttpPlugin的应用. ...

  5. 【Playwright+Python】手把手带你写一个自动化测试脚本

    ​ 如何使用代理方式打开网页 在 playwright.chromium.launch() 中传入 proxy 参数即可,示例代码如下: 1.同步写法: 1 from playwright.sync_ ...

  6. Spring注解之依赖注入@Autowired和@Resource

    Spring常见的DI方式 字段注入(Field Injection) 在字段上使用@Autowired/Resource注解 字段注入是日常开发中使用最多的一种注入方式,它的实现代码如下: @Aut ...

  7. Oracle 字符串分割,并将内码转中文(简单实现),项目实战

    导读 实际项目开发过程中,可能会遇到这种情况,A表中A1字段存储B表中的内码如(1,2,3),此时需要将A表中的A1字段转中文,为了方便理解,我们这里创建学生表和老师表,一个学生对应N个老师. 创建表 ...

  8. 把nodejs程序打包成可执行文件

    在写好之后的nodejs程序,想发给同事的电脑上运行程序,就不得不下载node环境,还要安装第三方依赖包,非常的麻烦. 因此,可以借助一些插件来完成nodejs程序的打包,变成可以执行的文件. 将No ...

  9. 洛谷P2658

    我在洛谷第一次发个题解,管理员居然把这题的题解通道关了.... 看到好像没有优先队列的题解,来水一手 思路 形似A* 却不是A* 只需要求出其中一个点到其他点的D系数,所有D系数的最大值即是答案. 数 ...

  10. 数据存储为json或数据库

    1.数据存储 In [ ]: import requests from bs4 import BeautifulSoup rqq = requests.get('http://www.tipdm.co ...