C语言笔记2 --新手常常犯的错误之scanf()

接着上次的输出函数,这次我们来细细的讲一下输入函数:

scnaf();

同学们在第一节C语言课上,老师还没要求我们从键盘输入数据,只是单纯的声明变量,用一些基本运算符输出结果。而在C语言中,有着输出,必然有着输入,就像英语中有 you,那么肯定也有 I.
在用这个函数的时候同学们常常会出一些小毛病,而这些毛病,对于刚刚进入编程大门的同学来说,是很难发现的。
这里我稍微详细的介绍下这个与输出对应的函数,输入。
写一个简单的输入函数的格式:

scanf(" 格式化字符串 ", 地址列表);

有观察到这里与printf函数极其相似嘛,双引号,逗号,分号。
格式化字符串与printf函数一样,也是由 % + x 构成:

%d %c %s %e %u

与printf不同的是,这里逗号右边是地址列表,同学们在写代码的时候,有没有好奇为啥要用到 & 这个符号?
这个符号在C语言中,在这个函数里面叫做 “取地址符”。
同学们记得第一节课老师讲的关于计算机中地址的概念嘛?
在我们声明变量的时候,编译器就会帮助我们为这个变量开辟一定大小的地址空间,用来存放数据,例如:

int num1, num2;          //开辟两个大小为4个字节的整形变量
double num3, num4;       //开辟了两个大小为8个字节的双精度变量

这里的地址是一个标识,让我们知道这个数据存放的位置。相当于你点外卖的时候,告诉商家你的地址是在XXXXX学校XX宿舍501号 这样的。外卖相当于是数据,当外卖小哥把外卖送你宿舍的时候,也就相当于把数据存进了地址。
这里的 & 作用就是告诉scanf函数这个我输入的数据是要存进这个地址的,也可以说是写进这个地址。
知道了这些之后,我们再来看下这个函数怎么用:
比如我想求两个整形变量相加减,那么首先我肯定是要先有这两个整形变量存在,不存在我数据放哪去?外卖小哥的外卖送去哪?
所以

int n1, n2;  //声明两个整形变量

接下来输入,往这两个变量里面写入数据,这时候,我们的scanf函数就派上用场啦:

scanf("%d %d", &a, &b);

这里要解释一点 : 在格式控制字符串里面,一般都不需要添加任何字符的,有些同学喜欢在里面加上逗号:

scnaf("%d,%d", &a, &b);

这就导致你在输入数据的时候,也要把逗号输入进去。
可是这是为什么呢?
因为,在我们把数据从键盘敲进显示屏的时候,这些数据会以ASCII码的形式存在 ”缓冲区", 例如我输入12 74. 那么此时存在缓冲区的数据就是3132 3734 (ASCII码),然后scanf会从缓冲区扫描过去,从缓冲区读走一个字符,相当于清空缓冲区,直到结束。
也许会有同学有疑问,这个中间有空格咋办?
这个不用担心,scanf会自动忽略这样的空白字符,如大段空格,tab,回车。
也许还会问这个读走的是ASCII码呀,可是我要的是十进制的啊?
这个也不用担心,scanf会帮我们转换成对应的的数据类型。
然后我们在回头看一下,为啥要输入逗号呢?因为在输入数据的时候,若是没有空格,scanf在扫描数据的时候,本来要写入变量b地址的数据,写进了逗号,故变量b也就没写入数据。
用运行结果来看:
在这里插入图片描述
变量b的值还是系统随机分配的垃圾值(此值为上一个程序用过该地址后,未清空留下的值。比如有个程序利用了这块地址,假设地址为0x93fb78, 里面的数据为 -1234567. 用完之后里面的值没有清空,那么在我这个代码中,变量b恰好分配到了这个地址,而我还未对该变量进行赋值操作,由系统分配,那么该值就是上一次遗留的数据,也就是-1234567)。

若我b 赋初始值为 0 呢?

这就很直观的反映了我输入的数据74 并没有写入进b的地址,造成了数据丢失。
所以,在我们不是特别要求的情况下,最好还是不要在scanf函数里面加东西,直接写成:

scanf("%d %d",&n1, &n2);
scanf("%d%d",&n1, &n2);   //%d%d之间可以空格,也可以不用空格隔开

上面的对scanf忽略空白符的描述也可以作为理解输入数据的时候,为什么可以用回车隔开,也可以空格很多次,而不影响数据的写入的理论基础。

如果说printf是拼图的时候一块块拼图,那么scanf函数就是拼图的建造者(数据写入)
它告诉printf函数这块拼图该往哪儿拼(数据输出)
这里我要对 取地址 & 讲下我在学习C语言时候的理解:
取地址,我把地址理解为计算机中一个个小盒子,这个盒子叫做地址,
取地址的时候就是把这个盒子给拿出来,scanf函数从键盘获取数据的时候,
把数据放进这个小盒子,在把盒子放到它原来的位置。
不同的数据类型对应着不同大小的盒子,double最大,int相对较小,而且double这个盒子能装水(浮点,浮这个词我想像成水<–浮力),int类型的却不行,换句话说,double和int存放的数据类型是不一样的。
这样去看待的话是不是很好理解呢?


scnaf函数作为数据的写入,有一个缺陷,在写入字符数组数据的时候,只会读取第一个空格前的字符数据:
在这里插入图片描述
同学们看到空格是不是联想到了前面的 scanf会忽略空白符 呢?它在读取到第一个空格的时候就误认为数据已经完毕了,所以把空格前的 Today 写进了字符变量 str 在的地址。
后面的数据就存在了缓冲区。这也是scanf函数的一个缺陷。
ps: 在用scanf函数对字符串进行操作的时候,不需要取地址符, 因为数组名就是这个变量的首地址。
为了解决这个缺陷,我们需要用到gets()函数来输入字符串数据:
在这里插入图片描述

关于scanf函数的问题就先讲到这里了,最后再次总结下关于scanf函数涉及到的几个方面:
0:取地址符
1:scanf会忽略空白符
2:输入数据的时候,格式要跟 ”格式控制字符串“ 一样。有逗号输入逗号,无逗号用空白符隔开数据即可。
3:数据在缓冲区,scanf读取数据,转换成我们需要的,清空缓冲区。

(如有错误欢迎指出)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

C01acat

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值