我们在写C程序时,经常使用scanf函数,让用户输入数据,可是有时候会出现一些很奇怪的问题。例如,下面的程序是一个简单的四则运算:

#include <stdio.h>

int main()
{
char ope = '\0';//操作符+ - * /
int para1 = 0, para2 = 0, result = 0;//para1是运算参数1,para2是运算参数2,result是运算结果 printf("请输入第一个运算参数\n");
scanf("%d",¶1);
printf("请输入运算符 '+ - * /'\n");
scanf("%c",&ope);
printf("请输入第二个运算参数\n");
scanf("%d",¶2);
switch(ope)
{
case '+': result = para1 + para2;//如果运算符是+,就执行加法运算
break;
case '-': result = para1 - para2;//如果运算符是-,就执行减法运算
break;
case '*': result = para1 * para2;//如果运算符是*,就执行乘法运算
break;
case '/': result = para1 / para2;//如果运算符是/,就执行除法运算
break;
default: printf("运算符输入错误\n");//
break;
}
printf("运算结果是: %d\n", result);
return 0;
}

此程序不管从语法,还是逻辑上,都没有问题,且编译也能通过。实际运行时,却是如下结果:

在用户输入第一个运算参数后,按照程序的设定,应该让用户输入运算符,可是直接让用户输入第二个运算参数了。你能看出这是为什么吗? 

我们修改下程序,如下:

#include <stdio.h>

int main()
{
char ope = '\0';//操作符+ - * /
int para1 = 0, para2 = 0, result = 0;//para1是运算参数1,para2是运算参数2,result是运算结果 printf("请输入第一个运算参数\n");
scanf("%d",¶1);
printf("请输入运算符 '+ - * /'\n");
scanf("%c",&ope); printf("运算符是: %d\n", ope);
printf("请输入第二个运算参数\n");
scanf("%d",¶2);//加入这两行代码
switch(ope)
{
case '+': result = para1 + para2;//如果运算符是+,就执行加法运算
break;
case '-': result = para1 - para2;//如果运算符是-,就执行减法运算
break;
case '*': result = para1 * para2;//如果运算符是*,就执行乘法运算
break;
case '/': result = para1 / para2;//如果运算符是/,就执行除法运算
break;
default: printf("运算符输入错误\n");//
break;
}
printf("运算结果是: %d\n", result);
return 0;
}

我们加入两行代码,输出字符参数ope的ASCII码值,结果如下:

可以看到,ope的ASCII码值是10,正是换行符的ASCII码值。我们什么时候把换行符给了ope?

其实,在我们给运算参数para1赋值1的时候,我们按下了回车键,准备输入运算符,可是系统不懂啊,系统把回车键理解为换行符赋值给了ope,所以接下来会跳过让用户输入运算符而直接让用户输入运算参数2了,问题就在这里。

知道了问题所在,那么就好解决了。
请看:

#include <stdio.h>
#include <conio.h> int main()
{
char ope = '\0';//操作符+ - * /
int para1 = 0, para2 = 0, result = 0;//para1是运算参数1,para2是运算参数2,result是运算结果 printf("请输入第一个运算参数\n");
scanf("%d",¶1);
getchar(); printf("请输入运算符 '+ - * /'\n");
scanf("%c",&ope);
getchar();
printf("运算符是: %d\n", ope);
printf("请输入第二个运算参数\n");
scanf("%d",¶2);
switch(ope)
{
case '+': result = para1 + para2;//如果运算符是+,就执行加法运算
break;
case '-': result = para1 - para2;//如果运算符是-,就执行减法运算
break;
case '*': result = para1 * para2;//如果运算符是*,就执行乘法运算
break;
case '/': result = para1 / para2;//如果运算符是/,就执行除法运算
break;
default: printf("运算符输入错误\n");//
break;
}
printf("运算结果是: %d\n", result);
return 0;
}

在每次scanf结束后,加入getchar函数,即可。getchar函数从输入流中读取一个字符,因此可以接收我们每次按下的回车键,也就是换行符。运行结果如下:

调用scanf函数的一个陷阱的更多相关文章

  1. Android中调用C++函数的一个简单Demo

    这里我不想多解释什么,对于什么JNI和NDK的相关内容大家自己去百度或谷歌.我对Android的学习也只是个新手.废话少说直接进入正题. 一.在Eclipse中创建一个Android Applicat ...

  2. Delphi中返回类型为string的函数的一个陷阱(不是很懂)

    如果类的一个成员函数的返回值是string类型,需要注意一个问题 其返回值可能是错误的 例如函数的实现如下 function GetString( s: string ): string;begin  ...

  3. C语言scanf函数详细解释

    原文链接 函数名: scanf 功 能: 执行格式化输入 用 法: int scanf(char *format[,argument,...]); scanf()函数是通用终端格式化输入函数,它从标准 ...

  4. scanf函数

    一. 变量的内存分析 1. 字节和地址 为了更好地理解变量在内存中的存储细节,先来认识一下内存中的“字节”和“地址”. 1> 内存以“字节为单位” 0x表示的是十六进制,不用过于纠结,能看懂这些 ...

  5. 【C语言】05-printf和scanf函数

    一.printf函数 这是在stdio.h中声明的一个函数,因此使用前必须加入#include <stdio.h>,使用它可以向标准输出设备(比如屏幕)输出数据 1.用法 1> pr ...

  6. 黑马程序员——C语言基础 scanf函数 基本运算 三目运算符

    Java培训.Android培训.iOS培训..Net培训.期待与您交流! (一下内容是对黑马苹果入学视频的个人知识点总结) (一)scanf函数 1>  简单介绍一下scanf函数   这是在 ...

  7. 【学习笔记】【C语言】scanf函数

    1. 简介 这也是在stdio.h中声明的一个函数,因此使用前必须加入#include <stdio.h>.调用scanf函数时,需要传入变量的地址作为参数,scanf函数会等待标准输入设 ...

  8. C语言第五节scanf函数

    变量的内存分析 字节和地址 为了更好地理解变量在内存中的存储细节,先来认识一下内存中的"字节"和"地址". 内存以"字节为单位" 0x表示的 ...

  9. 【C语言】03-printf和scanf函数

    一.printf函数 这是在stdio.h中声明的一个函数,因此使用前必须加入#include <stdio.h>,使用它可以向标准输出设备(比如屏幕)输出数据 1.用法 1> pr ...

随机推荐

  1. 关于VS编译DevExpress默认产生几个多余的语言包的问题解决

    原文 关于VS编译DevExpress默认产生几个多余的语言包的问题解决 VS15开始对于非系统的Dll都会默认复制到本地,即bin\debug下面,复制dll到本地好处在于发布的时候不用再去寻找相关 ...

  2. UWP ListView嵌套ListView

    要求:加载全部的订单,每个订单里面有一个或者多个产品,在列表中要展现出来, 1. xaml界面 步骤:1.这里使用的是x:bind绑定所以要引入实体类命名空间(OrderList集合中类的命名空间): ...

  3. isHiden和isVisible的区别(可是有nativeEvent进行设置)

    之前一直对isHiden和isVisible的区别比较模糊,都是乱用的.今天因需要仔细看了一下. 1.isHiden只是返回部件的隐藏属性,并不能表示部件当前的真实状态.比如A部件有个子部件B,而A处 ...

  4. 使用VS将 XML/Json 转为Model Class文件

    环境: VS2015 Win10   XML例子: <OTA_GetRerStatusRQ EchoToken=" B3BB9248255BD851AC94" UserNam ...

  5. QT---Native Wifi functions 应用(WiFi有密码连接)

    实现功能     无线网卡列表     无线热点扫面     无线连接(有密码,配置文件连接方式)     无线断开     重命名本地无线名(两种方式)     删除无线配置文件     开启和关闭 ...

  6. C++ 使用回调函数的方式 和 作用。 持续更新

    先看两个demo: 一.在类test1中调用函数print() ,把print()的函数指针传递给test1的函数指针参数 test1.h: #include <stdio.h> #inc ...

  7. 发现 TSplitter 在嵌套时不好用, 索性写了个替代品(处理MouseDown,MouseMove,MouseUp,然后设定控件的Left值就可以了)

    代替 TSplitter 的 TDirPanel 类: unit DirPanel; interface uses   Classes, Controls, Forms, ExtCtrls; type ...

  8. 以太网,IP,TCP,UDP数据包分析(此文言简意赅,一遍看不懂的话,耐心的看个10遍就懂了,感谢作者无私奉献)

    1.ISO开放系统有以下几层: 7 应用层 6 表示层 5 会话层 4 传输层 3 网络层 2 数据链路层 1 物理层 2.TCP/IP 网络协议栈分为应用层(Application).传输层(Tra ...

  9. 【转载】Spring Boot引起的“堆外内存泄漏”排查及经验总结

    背景 为了更好地实现对项目的管理,我们将组内一个项目迁移到MDP框架(基于Spring Boot),随后我们就发现系统会频繁报出Swap区域使用量过高的异常.笔者被叫去帮忙查看原因,发现配置了4G堆内 ...

  10. 快速开发第一个SpringBoot应用

    通过笔者这段实践SpringBoot的学习,发现自从使用了SpringBoot后,就再也回不去SpringMVC了,因为相比于SpringMVC,SpringBoot真是太高效率了.下面我们看看它效率 ...