#include<stdio.h>
int main()
{
int x,sum1,sum2;
sum1=0;
sum2=0;
printf("请输入一些整数(输入0时结束输入):");
scanf("%d",&x);
while(x!=0)
{
if(x>0)
sum1=sum1+x;
else
sum2=sum2+x;
}
printf("大于0的整数的和为:%d\n");
printf("小于0的整数的和为:%d\n");
return 0;
}
while(1)
{
scanf("%d",&x);
if (x == 0) break;
if(x>0)
sum1=sum1+x;
else
sum2=sum2+x;
}
有的时候,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);