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

  1. #include <stdio.h>
  2.  
  3. int main()
  4. {
  5. char ope = '\0';//操作符+ - * /
  6. int para1 = 0, para2 = 0, result = 0;//para1是运算参数1,para2是运算参数2,result是运算结果
  7.  
  8. printf("请输入第一个运算参数\n");
  9. scanf("%d"1);
  10. printf("请输入运算符 '+ - * /'\n");
  11. scanf("%c",&ope);
  12. printf("请输入第二个运算参数\n");
  13. scanf("%d"2);
  14. switch(ope)
  15. {
  16. case '+': result = para1 + para2;//如果运算符是+,就执行加法运算
  17. break;
  18. case '-': result = para1 - para2;//如果运算符是-,就执行减法运算
  19. break;
  20. case '*': result = para1 * para2;//如果运算符是*,就执行乘法运算
  21. break;
  22. case '/': result = para1 / para2;//如果运算符是/,就执行除法运算
  23. break;
  24. default: printf("运算符输入错误\n");//
  25. break;
  26. }
  27. printf("运算结果是: %d\n", result);
  28. return 0;
  29. }

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

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

我们修改下程序,如下:

  1. #include <stdio.h>
  2.  
  3. int main()
  4. {
  5. char ope = '\0';//操作符+ - * /
  6. int para1 = 0, para2 = 0, result = 0;//para1是运算参数1,para2是运算参数2,result是运算结果
  7.  
  8. printf("请输入第一个运算参数\n");
  9. scanf("%d"1);
  10. printf("请输入运算符 '+ - * /'\n");
  11. scanf("%c",&ope);
  12.  
  13. printf("运算符是: %d\n", ope);
  14. printf("请输入第二个运算参数\n");
  15. scanf("%d"2);//加入这两行代码
  16. switch(ope)
  17. {
  18. case '+': result = para1 + para2;//如果运算符是+,就执行加法运算
  19. break;
  20. case '-': result = para1 - para2;//如果运算符是-,就执行减法运算
  21. break;
  22. case '*': result = para1 * para2;//如果运算符是*,就执行乘法运算
  23. break;
  24. case '/': result = para1 / para2;//如果运算符是/,就执行除法运算
  25. break;
  26. default: printf("运算符输入错误\n");//
  27. break;
  28. }
  29. printf("运算结果是: %d\n", result);
  30. return 0;
  31. }

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

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

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

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

  1. #include <stdio.h>
  2. #include <conio.h>
  3.  
  4. int main()
  5. {
  6. char ope = '\0';//操作符+ - * /
  7. int para1 = 0, para2 = 0, result = 0;//para1是运算参数1,para2是运算参数2,result是运算结果
  8.  
  9. printf("请输入第一个运算参数\n");
  10. scanf("%d"1);
  11. getchar();
  12.  
  13. printf("请输入运算符 '+ - * /'\n");
  14. scanf("%c",&ope);
  15. getchar();
  16. printf("运算符是: %d\n", ope);
  17. printf("请输入第二个运算参数\n");
  18. scanf("%d"2);
  19. switch(ope)
  20. {
  21. case '+': result = para1 + para2;//如果运算符是+,就执行加法运算
  22. break;
  23. case '-': result = para1 - para2;//如果运算符是-,就执行减法运算
  24. break;
  25. case '*': result = para1 * para2;//如果运算符是*,就执行乘法运算
  26. break;
  27. case '/': result = para1 / para2;//如果运算符是/,就执行除法运算
  28. break;
  29. default: printf("运算符输入错误\n");//
  30. break;
  31. }
  32. printf("运算结果是: %d\n", result);
  33. return 0;
  34. }

在每次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. HTTP的请求方法一共有9种,有OPTIONS, HEAD, GET, POST等等(消息头有图,十分清楚)

    请求方法:指定了客户端想对指定的资源/服务器作何种操作 下面我们介绍HTTP/1.1中可用的请求方法: [GET:获取资源]     GET方法用来请求已被URI识别的资源.指定的资源经服务器端解析后 ...

  2. 改善C#程序的建议6:在线程同步中使用信号量

    原文:改善C#程序的建议6:在线程同步中使用信号量 所谓线程同步,就是多个线程之间在某个对象上执行等待(也可理解为锁定该对象),直到该对象被解除锁定.C#中对象的类型分为引用类型和值类型.CLR在这两 ...

  3. QML于C++交互之信号与槽(signal&slot )

    connect c++ SIGNAL with QML SLOT 简介 QML 与 C++ 混合编程时,总结了一下qml和c++互相直接调用.及信号与槽连接 的几种情况,详细使用情况看示例代码 所有的 ...

  4. [Erlang-0015][Lager] Erlang日志框架Lager简析

    项目地址:https://github.com/basho/lager (欢迎任何形式的转载,但请务必注明出处:http://www.cnblogs.com/liangjingyang)

  5. postman --- 如何在用户登陆和CSRF验证的场景下使用

    一.前提 安装postman和Postman Interceptor postman应用放到桌面: 二.用户登陆 这种场景很简单,只要开启Interceptor,然后先请求登陆地址,再继续请求其他地址 ...

  6. http协议内容展示以及如何用telnet发送请求

    1.http协议组成: 报文首部:状态行(请求行) 请求首部字段 通用字段 其他信息 空行 报文主体 GET请求头: GET /test.php?a=1 HTTP/1.1 Host: localhos ...

  7. jmeter模拟spike测试(尖峰测试)

    概述 尖峰测试(Spike testing)在性能测试中属于压力测试的一个子集.指的是在某一瞬间或者多个频次下用户数和压力陡然增加的场景. 为了验证我们的网站在访问用户急剧增加的情况下,或者短时间内反 ...

  8. 附006.Kubernetes RBAC授权

    一 RBAC 1.1 RBAC授权 基于角色的访问控制(RBAC)是一种基于个人用户的角色来管理对计算机或网络资源的访问的方法. RBAC使用rbac.authorization.k8s.io API ...

  9. Django框架之前端渲染-模板层

      Django 模板层   Django 模板层 前后端数据传递 (1) 后端朝前端页面传递数据的方式: # 将当前所在的名称空间中的名字全部传递给前端页面 # 第一种 return render( ...

  10. 迁移桌面程序到MS Store(9)——APPX With Desktop Extension

    在<迁移桌面程序到MS Store(8)——通过APPX下载Win32Component>中我们讨论了通过APPX来下载Service部分的安装包.但是纯UWP的客户端并不能自动运行下载的 ...