scanf对字符串、字符及其他变量的输入细节

前言

作为一个高一就接触C语言的老玩家,写这篇博客给我有一种返祖的感觉,毕竟scanf是我第一天就学的东西……
但是很无奈,前些天的C语言考试,就是死在了输入这边。逻辑轻松秒杀,数据就是怎么都输入不对。离谱的scanf,以前都是用cin习惯了,现在个人感觉上级小考最难的就是scanf……
网络上的详解不够“亲民”,我在这里特地做了一个亲民的教程,保证能够真正学会使用scanf。

文章中华,我总结了一个scanf通用公式,用伪代码的形式给出了scanf的输入逻辑。可以完美应对期末考试的scanf输入问题,不会出现错输入,少输入的情况

废话不多说,为了我的期末,开干

scanf忽略空格

scanf("%d%d%d",&m,&n,&p);
printf("%d %d %d\n",m,n,p);

scanf在输入整形数据的时候(当然也包括浮点数据、长整型等数据等等),中间的%d标志是没有必要加上空格的。scanf以键盘中输入的空格为结束标志(因为空格对于%d来说是非法的,因此scanf会作为结束标志,如果输入了多个空格,那么就会直接跳过。空格对于%s也是非法的,也会作为结束标志,在出现多个空格的时候,也会直接跳过)
也就是说,在上述的scanf中,随便输入几个空格都是可以的。就像这个样子……从图片中我们可以看出来,这些数据都是能够正常读出来的。
在这里插入图片描述
当然,回车符号‘\n’也是作为%d的非法标志,也是能够充当结束的角色。
例如下面,同样的代码
在这里插入图片描述
即使我这么肆无忌惮地输入,程序照样能够正确地读出我的数据。
总结:scanf以当前数据类型的非法输入作为结束标志,如果有多个非法输入,那么就会直接跳过,直到找到合法输入为止。

scanf的执行逻辑

有的时候,scanf会出现空格与回车
例如这样子

scanf("%d %d %d",&m,&n,&p);
printf("%d %d %d\n",m,n,p);

在这里插入图片描述
这样的输入看起来很正常,也没什么问题,但是这个背后却蕴藏着scanf执行的根本逻辑。
我来给你一一推演
让我们把目光聚焦到scanf的函数原理上
我们首先把scanf的字符串实参拿出来
也就是“%d %d %d”
现在我们定义一个指针p,p指向这个字符串的第一个字符,也就是‘%d’
接下来scanf会从输入缓冲区开始比较,输入缓冲区就是你在黑黑的窗口里面输入的东西。
显然,我们输入的东西是这些字符
‘7’‘ ’‘8’‘ ’‘9’‘\n’一共六个字符(包括空格!)
注意,为了方便后面的推演,这里我们假设整数、实数等都是“一个字符”,%d等也是“一个字符”
也就是说,‘234’是一个字符

假设我们再定义一个指针q,它指向输入缓冲区的第一个字符
接下来scanf就会开始比对
如果q指向的内容是scanf所需的,那么q和p同时往后移动一位,并且对应向scanf输入q指向的内容。
如果不是所需的,那么q往后移动,p仍然卡在原位置,等待正确数据的输入。
写成代码就会是这个样子
你会发现,下面这个逻辑代码,也是完全符合我上面提到的总结。

q=缓冲区字符串首地址;
for(p=scanf字符串首地址;p<=scanf字符串首地址+strlen(scanf字符串);p++){
	if(q<=缓冲区字符串首地址+strlen(缓冲区字符串)){
		if(*p和*q属于同一类型){
			输入q;
			q++;
		}else{
			q++;
		}	
	}else{
		输入结束;
	}
}

根据这个逻辑推演上面scanf,也是成立的。
需要注意的是,如果有多个scanf,缓冲区是不会清空的,例如你可能会碰见这种情况:

scanf("%d",&n);
gets(ss);

gets仅以\n作为非法字符,其它几乎所有字符都是通吃
但是你的输入是,一个整形,然后回车,输入一个字符串
当你以为你成功地输入了字符串时,结果在输入一个整形并回车的时候,就已经结束了
因为在你按回车的时候,'\n’保留在了输入缓冲区中,scanf输入字符串没有\n,所以输入完整形后,scanf就已经退出了。\n就会留在输入缓冲区中,但是gets以回车符号结尾,那么都不等你输入,gets就已经结束了
解决的办法就是加上一个\n让scanf吸收就行

scanf("%d\n",&n);
gets(ss);

你可能还会发现:既然gets以回车作为非法字符,那我不打回车不就可以了吗?
还真是这样。
在不打回车,直接继续输入的情况下,就是正确的
因为字母对于%d来说是一个非法的东西,所以会直接作为结束标志。
在这里插入图片描述
因此,我想说的是,不要再听别人说,什么scanf以XXX作为结束标志,还各种分类讨论,其实,本质上就是以非法字符作为结束标志,一旦类型对不上号,就可以直接结束,没必要给空格或者回车搞特殊,字母也一样可以作为结束标志。
如果还有人觉得空格或者回车是什么特殊角色,那就很有必要看看这个,%c吸收空格和回车

scanf("%d%c",&n,&c);
gets(ss);
printf("%d %s",n,ss);

这样就可以实现不使用\n也可以成功输入ss,当然,原理也是吸收掉回车符号
如果你在输入整形之后再输入一个空格,然后再输入字符串,输出也是没问题的
另外要说明一点,gets会自动吸收回车字符串,这样你在使用多个gets的时候,就可以不去考虑是否清空缓冲区的’\n’
就像这样子

gets(ss);
gets(ss2);
  • 84
    点赞
  • 345
    收藏
    觉得还不错? 一键收藏
  • 19
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值