调用scanf函数的一个陷阱
我们在写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函数的一个陷阱的更多相关文章
- Android中调用C++函数的一个简单Demo
这里我不想多解释什么,对于什么JNI和NDK的相关内容大家自己去百度或谷歌.我对Android的学习也只是个新手.废话少说直接进入正题. 一.在Eclipse中创建一个Android Applicat ...
- Delphi中返回类型为string的函数的一个陷阱(不是很懂)
如果类的一个成员函数的返回值是string类型,需要注意一个问题 其返回值可能是错误的 例如函数的实现如下 function GetString( s: string ): string;begin ...
- C语言scanf函数详细解释
原文链接 函数名: scanf 功 能: 执行格式化输入 用 法: int scanf(char *format[,argument,...]); scanf()函数是通用终端格式化输入函数,它从标准 ...
- scanf函数
一. 变量的内存分析 1. 字节和地址 为了更好地理解变量在内存中的存储细节,先来认识一下内存中的“字节”和“地址”. 1> 内存以“字节为单位” 0x表示的是十六进制,不用过于纠结,能看懂这些 ...
- 【C语言】05-printf和scanf函数
一.printf函数 这是在stdio.h中声明的一个函数,因此使用前必须加入#include <stdio.h>,使用它可以向标准输出设备(比如屏幕)输出数据 1.用法 1> pr ...
- 黑马程序员——C语言基础 scanf函数 基本运算 三目运算符
Java培训.Android培训.iOS培训..Net培训.期待与您交流! (一下内容是对黑马苹果入学视频的个人知识点总结) (一)scanf函数 1> 简单介绍一下scanf函数 这是在 ...
- 【学习笔记】【C语言】scanf函数
1. 简介 这也是在stdio.h中声明的一个函数,因此使用前必须加入#include <stdio.h>.调用scanf函数时,需要传入变量的地址作为参数,scanf函数会等待标准输入设 ...
- C语言第五节scanf函数
变量的内存分析 字节和地址 为了更好地理解变量在内存中的存储细节,先来认识一下内存中的"字节"和"地址". 内存以"字节为单位" 0x表示的 ...
- 【C语言】03-printf和scanf函数
一.printf函数 这是在stdio.h中声明的一个函数,因此使用前必须加入#include <stdio.h>,使用它可以向标准输出设备(比如屏幕)输出数据 1.用法 1> pr ...
随机推荐
- -bash: /root/java/jdk/bin/java: cannot execute binary file
错误 -bash: /root/java/jdk/bin/java: cannot execute binary file 错误原因 安装的Linux的版本是32位的,下载的软件是64位,版本不兼容, ...
- WPF Build Action
None: The file is not included in the project output group and is not compiled in the build process. ...
- 高斯判别分析模型( Gaussian discriminant analysis)及Python实现
高斯判别分析模型( Gaussian discriminant analysis)及Python实现 http://www.cnblogs.com/sumai 1.模型 高斯判别分析模型是一种生成模型 ...
- 使用 Visual Studio 开发并调试 Mail Add-in (mail app for Outlook)
准备工作 如果你的邮箱搭建在 Exchange Server 上,则可以创建邮件应用程序(Mail Add-in)来扩展Office本身的功能,使用 Office Add-in Model 开发的 M ...
- C#WinForm线程基类
在CS模式开发中一般我们需要用到大量的线程来处理比较耗时的操作,以防止界面假死带来不好的体验效果,下面我将我定义的线程基类给大家参考下,如有问题欢迎指正. 基类代码 #region 方法有返回值 // ...
- 将后台窗口激活到前台的方法(使用AttachThreadInput和SetForegroundWindow两个API)
下面这种方法是我见到的最理想的,还有一些其他的方法,像通过SetWindowsPos这个API设置窗口的Z-oder到最顶层,再设置回去.还有通过把当前窗口设置到底层,然后激活目标窗口等等方法. HW ...
- QT Udp组播(穿透)
http://blog.csdn.net/victoryknight/article/details/7814243 主题 UDPQt路由器 局域网内的两台机器如果隔有路由器,那么这两台机器之间不 ...
- android核心系列--1,组件生命周期
一,进程模型及进程托管 1,一个APP应用是由一个或多个组件构成的,这些组件可以运行在一个进程中,也可以分别运行在多个进程中: 进程的构造和销毁是由系统全权负责的. 2,一个应用进程只有一个应用环境对 ...
- 浅析C#代理
delegate 是委托声明的基础,是.net 的委托的声明的关键字action 是基于delegate实现的代理 有多个参数(无限制个数)无返回值的代理 func 是基于delegate实现的代理 ...
- [迟到的万圣节向]可怕的python
什么?python简单易懂好学可读性高灵活耐用扩展好? 预测下面几个小段落的输出,来看看这个能过几关? ============================ Stage 1 预测下列输出 def ...