出现的问题

  在做编程题的的时候,遇到了一个很奇怪的错误,出问题的代码如下:

 1 #include <cstdio>
2 using namespace std;
3
4 int main() {
5 int c;
6 bool b;
7 // printf("%p %p", &c, &b); // c的地址是:66fe1c,b的地址是:66fe1b
8 scanf("%d %d", &c, &b);
9 printf("c = %d b = %d", c, b);
10
11 return 0;
12 }

这是运行的结果:

  是不是觉得很奇怪?明明给变量c和变量b输入的是10和1,可是在输出的结果中,c的值为0。这是为什么呢?其中原因涉及到内存。大概的解释是,我通过%d占位符来为bool型变量b输入值,而系统为bool型的变量分配1个字节大小的内存,又因为通过%d输入的值是占4个字节大小的,所以由于变量b的内存不够,输入的值会占用到变量c的内存并且覆盖原来存储的值。下面,我将通过变量所对应的内存中发生的变化进行详细的解释。

详细解释

  通过打印输出变量c,b的地址,我们来绘制出相应的内存条:

  注意,由于我们在定义变量c,b时没有进行初始化,系统会为变量随机分配值,所以内存条应该是有相应的十六进制的值的,但图中为了方便,表示空白省略其中相应的值。

  为了能够更好地表示出其中的错误,我们会输入比较大的数字。

  这里我们还是先为变量c输入10,之后十进制10会转变为十六进制00 00 00 0A,倒着存储到变量c的内存中:

  在为变量b输入值之前,我们需要知道,在C++中,bool型变量的字节大小为1个字节,也就是sizeof(bool) == 1,但我们在scanf函数中通过%d占位符来为变量b读取值,又知道通过占位符%d的值是占4个字节的大小的,而b变量的内存大小为1个字节,很明显,是存储不了4个字节大小的值的,所以只能通过占用变量c的内存来存储(准确来说是占用了变量c的前3个字节的内存),导致原本存储在变量c内存中的值被覆盖。

  现在,我们为b变量输入180079837,再按照上述的说法,来看看内存发生了什么变化:

  首先十进制180079837会转变为十六进制0A BB CC DD,倒着存储到变量b的内存中,又因为变量b的内存只有1个字节的大小不够存储,所以会在接着的3个字节大小内存来存储,这就会导致属于变量c的内存被占用,我们输入的新值覆盖了原本的值。

  没错,这就是问题所在。现在我们来打印输出看看他们的值:

  嗯...又是些很奇怪的值,这是怎么读出来的呢?

  首先来看变量b,虽然我们为变量b输入的值是4个字节的大小,但由于变量b的所占的字节大小为1,所以系统自会只读66fe1b这个地址存放的值,十六进制DD对应着十进制的211,所以实际上b变量所存储的值是211。

  然后是变量c,因为变量c是int型变量,占用字节大小为4,所以系统会从66fe1c这个地址开始往后读4个字节大小的内存,这4个字节的内存就存储着变量c的值,我们读的顺序应该是00 0A BB CC,对应着十进制703436,所以变量就存储着703436,并打印输出之。

  通过,上面的解析,我们现在应该明白了一开始为什么我们输入 10 1 会出现 c = 0, b = 1 的情况了,就是下图的情况。

  所以有什么解决的方法呢?首先,bool型没有专门对应的占位符。所以如果想通过scanf函数来为bool变量进行输入,可以把该变量定义为int型并通过占位符%d进行输入,又或者是通过枚举来定义。而如果是C++的话,就更简单了,用cin来对bool型变量进行输入。

常用占位符

%d:输入/输出十进制整数。

%o:输入/输出八进制整数。

%x:输入/输出十六进制整数。

%u:输入/输出无符号型整数。

%hd:输入/输出十进制短整数。

%ld:输入/输出十进制长整数。

%lld:输入/输出十进制长长整数。

%ull:输入/输出十进制无符号长长整数。

(如果要输入/输出八进制或十六进制的数,只需要把d改为o或x)

%f:输入/输出单精度浮点数。

%lf:输入输出双精度浮点数。

%e:输入/输出科学计数。

%c:输入/输出一个字符。

%s:输入/输出字符串。

%p:输入/输出地址。

参考资料

https://tieba.baidu.com/p/7250200456

《C语言程序设计现代方法-第二版》

在scanf函数中占位符使用错误而产生的一些错误的更多相关文章

  1. scanf函数中*修饰符的作用,如:%*d

    在scanf函数中,*修饰符可以跳过所在项的输入.如下: #include <stdio.h> int main() { ; printf("请输入:"); scanf ...

  2. Spring中手动增加配置文件中占位符引用的变量

    在项目中遇到一个这样的需求,项目的配置文件由外部传入,这时spring配置文件那些占位符变量该如何取值呢? 解决这个问题的做法有几种,我想到的大概有以下三种: 1.通过系统属性来实现,把外部传入的配置 ...

  3. jpa的@Query中"?"占位符的使用小坑

    今天使用@Query自定义查询语句,出现了一个错误: java.lang.IllegalArgumentException: Parameter with that position [1] did ...

  4. C/C++ scanf 函数中%s 和%c 的简单差别

    首先声明:在键盘中敲入字符后,字符会首先保存在键盘缓冲区中供scanf函数读取(scanf.getchar等函数是读取缓冲区,getch函数是读取的控制台信息,即为直接从键盘读取).另外特别注意键盘上 ...

  5. printf函数中*修饰符的作用,如:%*d

    在printf函数中,我们可以用数字修饰来控制打印的字段宽度和精度,如下(为强调视觉效果,均填充0): #include <stdio.h> int main() { ; float f= ...

  6. Hql中占位符(转)

    在新的Hibernate 4版本中,对于Hql有一点点改变,如果你还是按照以前的方式去编写HQL并且用了以下占位符的方式,就会得到一个警告. 参考资料:https://hibernate.atlass ...

  7. Jfinal数据库操作语句中占位符的使用

    占位符的优点: 1.增加SQL代码可读性 2.占位符可以预先编译,提高执行效率 3.防止SQL注入 4.用占位符的目的是绑定变量,这样可以减少数据SQL的硬解析,所以执行效率会提高不少 假设要将id从 ...

  8. sprintboot 中占位符及多环境配置

    (原) 关于springboot中多环境配置问题 1.在application.properties文件中通过 spring.profiles.active=... 选择系统所要加载的配置文件,这里的 ...

  9. Scala学习笔记(六):本地函数、头等函数、占位符和部分应用函数

    本地函数 可以在方法内定义方法,这种方法叫本地函数,本地函数可以直接访问父函数的参数 def parent(x: Int, y: Int): Unit ={ def child(y:Int) = y ...

随机推荐

  1. Codeforces Round #666 (Div. 2) B. Power Sequence (枚举)

    题意:有一个长度为\(n\)的序列,你每次可以对序列重新排序,然后花费\(1\)使某个元素加减\(1\),多次操作后使得新序列满足\(a_{i}=c^i\),\(c\)是某个正整数,求最小花费. 题解 ...

  2. CodeCraft-20 (Div. 2) B. String Modification (字符串,规律)

    题意:有一个长度为\(n\)的字符串,你可以选取一个值\(k(1\le k \le n)\),然后遍历字符串,每次将区间长度为\(k\)的字符串反转,求反转后字典序最小的字符串,并输出\(k\)的值. ...

  3. 吉哥系列故事――恨7不成妻 HDU - 4507

    题目: 单身! 依然单身! 吉哥依然单身! DS级码农吉哥依然单身! 所以,他生平最恨情人节,不管是214还是77,他都讨厌! 吉哥观察了214和77这两个数,发现: 2+1+4=7 7+7=7*2 ...

  4. pillow KeyError: 'WEBP'

    描述 使用pillow库jpg转到webp报错 File "F:\Anaconda\lib\site-packages\PIL\Image.py", line 1983, in s ...

  5. IFIX 5.9 报警存sql

    环境 win7x64 + ifix 5.9 + sql server 2008 (sql 我装在了别的win10的机器上,和ifix的win7不在同一个机器,网是通的) 1 安装sql server ...

  6. Commons Collections2分析

    0x01.POC分析 //创建一个CtClass对象的容器 ClassPool classPool=ClassPool.getDefault(); //添加AbstractTranslet的搜索路径 ...

  7. μC/OS-III---I笔记1---概述

    在裸板上跑一些程序对于一些电子设计是足够的,所谓裸板上的程序就是传统的前后台系统,而我的理解它应该是一种"过程类"的程序,一个大循环(作为后台)做一些处理,中断程序(作为前台)来处 ...

  8. postion:fixed和margin:0 auto的使用

    很多同学将顶部菜单固定,使用postion:fixed,然后使用margin:0 auto进行居中,发现margin:0 auto并不起作用. 通常,我们要让某元素居中,会这样做: #element{ ...

  9. C# 6.0 Features , C# 7.0 Features

    1 1 1 C# 6.0 Features http://stackoverflow.com/documentation/c%23/24/c-sharp-6-0-features#t=20160828 ...

  10. Twitter 分享

    Twitter 分享 Twitter Share API https://twitter.com/intent/tweet?url= &text= demo ?url= https://www ...