赞
踩
基于这样一道题,做如下尝试:
主要想要知道,这个为什么只读入一个12.3,然后强转赋值给i以后,后面的值就不再被读入赋值给j和k了。还有就是为什么第一个浮点型会被读入,而不是识别到它与目标的格式不同就直接跳出。
从网上了解到,scanf是有一个缓存区的,如果缓存区里面有数据,就先从缓存区里面读入,如果没有,就要求客户进行输入。读入整型或者浮点型的时候,空格,回车和Tab键都是忽略的,而输入字符串的时候,是不会被忽略的。
scanf是有返回值的,scanf 函数的返回值反映的是按照指定的格式符正确读入的数据的个数。
如果输入数据与指定格式不符,则会产生输入错误。遇到输入错误,scanf函数会立即终止,返回已经成功读取的数据的个数。 所以,通过scanf函数的返回值和指定输入数据的个数(由格式符决定)的比较,可以判断数据输入是否成功。
然后我们开始做第一个尝试:
首先是返回值的尝试。
#include<stdio.h>
int main()
{
int i=0,j=0,k=0,re=0;
re = scanf("%d%d%d",&i,&j,&k);
printf("i = %d\n",i);
printf("j = %d\n",j);
printf("k = %d\n",k);
printf("re = %d\n",re);
return 0;
}
12.3
我们可以看到返回值是1,只有i有数值,且为12。
换几种输入方式:
12.3 12.1 12.0
12.1 1 5
15 12.3 5
通过以上试验,我们可以看到,不管输入多少,只要遇到浮点型,就会取整然后终止读入。不会影响它之前的读入,但之后的就不会再读入了。
#include<stdio.h> int main() { int i=0,j=0,k=0,re=0; //第一次 re = scanf("%d%d%d",&i,&j,&k); printf("i = %d\n",i); printf("j = %d\n",j); printf("k = %d\n",k); printf("re = %d\n",re); //第二次 re = scanf("%d%d%d",&i,&j,&k); printf("i = %d\n",i); printf("j = %d\n",j); printf("k = %d\n",k); printf("re = %d\n",re); //第三次 re = scanf("%d%d%d",&i,&j,&k); printf("i = %d\n",i); printf("j = %d\n",j); printf("k = %d\n",k); printf("re = %d\n",re); return 0; }
12.3
可以看到,后两次scanf都没有再读入就直接跳过了。
然后我们改一下代码,让读入一次以后的i赋值为0看一下。
#include<stdio.h> int main() { int i=0,j=0,k=0,re=0; //第一次 re = scanf("%d%d%d",&i,&j,&k); printf("i = %d\n",i); printf("j = %d\n",j); printf("k = %d\n",k); printf("re = %d\n",re); i = 0; //第二次 re = scanf("%d%d%d",&i,&j,&k); printf("i = %d\n",i); printf("j = %d\n",j); printf("k = %d\n",k); printf("re = %d\n",re); //第三次 re = scanf("%d%d%d",&i,&j,&k); printf("i = %d\n",i); printf("j = %d\n",j); printf("k = %d\n",k); printf("re = %d\n",re); return 0; }
12.3
这样看来,跟i的值是没有关系的,也确实证明,第二次、第三次是没有数据读入的。
#include<stdio.h> int main() { int i=0,j=0,k=0,re=0; float fl=0.0; //第一次 re = scanf("%d%d%d",&i,&j,&k); printf("i = %d\n",i); printf("j = %d\n",j); printf("k = %d\n",k); printf("re = %d\n",re); printf("fl = %f\n",fl); i = 0; //第二次 re = scanf("%f%d%d",&fl,&j,&k); printf("i = %d\n",i); printf("j = %d\n",j); printf("k = %d\n",k); printf("re = %d\n",re); printf("fl = %f\n",fl); //第三次 re = scanf("%d%d%d",&i,&j,&k); printf("i = %d\n",i); printf("j = %d\n",j); printf("k = %d\n",k); printf("re = %d\n",re); printf("fl = %f\n",fl); return 0; }
这一次的探索就有点意思了,输入第一次12.3的时候,只运行完第一次,第二次还让我继续输入,我再次输入12.3,然后结束了。
从这个结果里面,我们可以看到,12.3在被i读入取整以后,0.3被留在了缓存区,待到下一个读入%f的控制符出现的时候,会把它的小数值读入,然后会让用户继续输入数据,我再次输入12.3,j就成了12了,后面k的读入和第三次的读入都没有生效。
也就是一次输入浮点型,读入却是整型的时候,小数点后面的数据会被留在缓存区。那是不是后面的数其实不是没有读入,而是读入了0.3的0呢?这个就不知道如何尝试来获得这个结论了。但我们可以输入0.3看一下结果:
由此结果,大致能表明有那么一点可能性。
现在,也就是说,有两种可能:
1、scanf读入的过程中,读入12.3的时候,识别到有整数部分,就继续读入,到了.3的时候,不对劲,就跳出了,并且终止scanf(是不是确实终止了,等会试试),等到.3遇到可以被读入的控制符%f的时候,可以继续读入。
2、scanf读入的过程中,读入12.3的时候,识别到有整数部分,就继续读入,到了.3的时候,不对劲,然后后面的数据其实读入的是0.3的0,虽然读入了,但是这不是按照指定的格式符正确读入的数据的个数(这个一会也试试)。
先来第一种可能的吧:
把第一个读入的第二个控制符改为%f。
#include<stdio.h> int main() { int i=0,j=0,k=0,re=0; float fl=0.0; //第一次 re = scanf("%d%f%d",&i,&fl,&k); printf("i = %d\n",i); printf("j = %d\n",j); printf("k = %d\n",k); printf("re = %d\n",re); printf("fl = %f\n",fl); i = 0; //第二次 re = scanf("%f%d%d",&fl,&j,&k); printf("i = %d\n",i); printf("j = %d\n",j); printf("k = %d\n",k); printf("re = %d\n",re); printf("fl = %f\n",fl); //第三次 re = scanf("%d%d%d",&i,&j,&k); printf("i = %d\n",i); printf("j = %d\n",j); printf("k = %d\n",k); printf("re = %d\n",re); printf("fl = %f\n",fl); return 0; }
事实证明,scanf并不是终止了,如果下一个是要浮点型数据的话,它会读入0.3然后继续请求数据。这个可能不太明显,我再换一个数据输入:
这就可以明显看出,12.3是被i和fl进行读入了,然后要求输入k的值,我输入了56,也成功读入了。
也就是第一种可能比较合理的表达是:
1、scanf读入的过程中,读入12.3的时候,识别到有整数部分,就继续读入,到.3的时候,识别到不是想要的类型,就终止了%d的读入,并且.3留在了缓存区里面,这个scanf语句里后面如果有%f或者%lf(这个没理由不行),那么就继续读入,说明不是直接终止了scanf语句,而是会继续执行。
#include<stdio.h> int main() { int i=0,j=0,k=0,re=0; float fl=0.0; re = scanf("%f",&fl); printf("fl = %f\n",fl); printf("re = %d\n",re); re = scanf("%d%f",&i,&fl); printf("i = %d\n",i); printf("fl = %f\n",fl); printf("re = %d\n",re); re = scanf("%f",&fl); printf("fl = %f\n",fl); printf("re = %d\n",re); }
在刚才的输入输出中,发现了一个非常有意思的现象,用%f直接读入78.2的时候,输出观察到是78.199997,而通过先读入78,再读入0.2的话,就是i = 78,fl = 0.2。
然后就写了这个程序单独验证一下这个现象。
它的输出确实也说明这个现象是确定的,具体原理未知。
第二个可能里面那个
#include<stdio.h> int main() { int i=1,j=1,k=1,re=0; float fl=1.0; //第一次 re = scanf("%d%d%d",&i,&j,&k); printf("i = %d\n",i); printf("j = %d\n",j); printf("k = %d\n",k); printf("re = %d\n",re); printf("fl = %f\n",fl); i = 1; //第二次 re = scanf("%f%d%d",&fl,&j,&k); printf("i = %d\n",i); printf("j = %d\n",j); printf("k = %d\n",k); printf("re = %d\n",re); printf("fl = %f\n",fl); //第三次 re = scanf("%d%d%d",&i,&j,&k); printf("i = %d\n",i); printf("j = %d\n",j); printf("k = %d\n",k); printf("re = %d\n",re); printf("fl = %f\n",fl); return 0; }
这个的改动很简单,既然怀疑是后面都被0.3的0赋值了,那就初始值不设为0,用1来试。
这个结果就证明了,后面确实不是读入的0.3的0,缓存区里面更像是.3。第二个可能推翻。
这个是从网上看到,有一个scanf缓存区清空的代码:
rewind(stdin);
然后用这个做一个验证,它的作用跟用%f读一下其实差不多。
#include<stdio.h> int main() { int i=0,j=0,k=0,re=0; float fl=0.0; //第一次 re = scanf("%d%d%d",&i,&j,&k); printf("i = %d\n",i); printf("j = %d\n",j); printf("k = %d\n",k); printf("re = %d\n",re); printf("fl = %f\n",fl); //rewind(stdin); //第二次 //re = scanf("%f%d%d",&fl,&j,&k); re = scanf("%d%d%d",&i,&j,&k); printf("i = %d\n",i); printf("j = %d\n",j); printf("k = %d\n",k); printf("re = %d\n",re); printf("fl = %f\n",fl); //第三次 re = scanf("%d%d%d",&i,&j,&k); printf("i = %d\n",i); printf("j = %d\n",j); printf("k = %d\n",k); printf("re = %d\n",re); printf("fl = %f\n",fl); return 0; }
注释掉rewind(stdin);的时候:
就是最开始那个效果。
#include<stdio.h> int main() { int i=0,j=0,k=0,re=0; float fl=0.0; //第一次 re = scanf("%d%d%d",&i,&j,&k); printf("i = %d\n",i); printf("j = %d\n",j); printf("k = %d\n",k); printf("re = %d\n",re); printf("fl = %f\n",fl); rewind(stdin); //第二次 //re = scanf("%f%d%d",&fl,&j,&k); re = scanf("%d%d%d",&i,&j,&k); printf("i = %d\n",i); printf("j = %d\n",j); printf("k = %d\n",k); printf("re = %d\n",re); printf("fl = %f\n",fl); //第三次 re = scanf("%d%d%d",&i,&j,&k); printf("i = %d\n",i); printf("j = %d\n",j); printf("k = %d\n",k); printf("re = %d\n",re); printf("fl = %f\n",fl); return 0; }
现在打开那个注释:
我们可以看到,第二次的输入就不受影响了。这就说明缓存区里面的.3被清空以后,读入又重新进行了。
scanf读入的过程中,读入12.3的时候,识别到有整数部分,就继续读入,到.3的时候,识别到不是想要的类型,就终止了%d的读入,并且.3留在了缓存区里面,这个scanf语句里后面如果有%f或者%lf(这个没理由不行)或者清空缓存区,那么就继续读入,说明不是直接终止了scanf语句,而是会继续执行。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。