在六天前,也就是10月21日,我受某位学长怂恿去了HDOJ看看,结果被虐的不要不要的。我当时连while语句都不知道诶,英语也不好,连题干都看不懂,
题是这样的
Problem Description
Calculate A + B.
Input
Each line will contain two integers A and B. Process to end of file.
Output
For each case, output A + B in one line.
Sample Input
1 1
Sample Output
2
第一遍是我还真的以为是简单的算一遍A+B呢,当然没有通过啦。有位同级大佬告诉我不是算一次就行的,还要接着算。直到今天(27日)才看到开头有一个EACH,好吧,真实人生一大悲哀。
可以AC的代码是这样的
#include<stdio.h>
int main()
{
int a,b;
while(scanf("%d%d",&a,&b)!=EOF)
{
printf("%d\n",a+b);
}
return 0;
}
那么scanf后为什么非要加一个!=EOF呢?
下面这篇博文和学长大佬都说ACM是靠导入文件读取数据的,EOF表示文件尾,读取到就跳出循环,不加EOF没有这个效果
从while(scanf() != EOF)说到ACM OnlineJuge的评判原理.
《C Primer Plus中文第六版》220页提到,C的输入函数内置了文件结尾检测器。
检测文件结尾的一种方法是:在文件末尾放一个特殊的字符标记文件结尾,例如内嵌的Ctrl+Z字符。
另一种方法是:存储文件大小的信息。如果文件有3000字节,读到3000字节时便达到文件末尾。
读取到文件末尾时,getchar()和scanf()会返回一个特殊值EOF(end of file缩写),EOF定义在stdio.h中:#define EOF (-1)
所以,while(scanf("%d%d",&a,&b)!=EOF)加上!=EOF的作用就是,读取到文件末尾时可以跳出循环。如果不加,无法跳出while(),系统判定超时。
接下来是一些题外话?
之前总有一种执念,以为scanf的返回值为-1或0时自动跳出while(),现在想想真是脑袋被门夹了,捂脸捂脸~
scanf()返回类型为int,返回值为成功读取的项数
读取失败时返回值为0
检测到文件末尾或硬件问题时返回值为-1
使用%d转换说明读取时,scanf()每次读取一个字符,跳过所有空白符,直至遇到第一个非空白字符才开始读取,如果找到一个数字或符号(+/-),便开始读取保存字符,直至遇到非数字字符。
如果第一个非空白符不是数字,scanf()停在那里,把字符放入输入中,不会把值赋给指定变量。在下一次读取时,首先读取到的还是该字符,scanf()始终无法越过该字符,且此时scanf()返回值为0,上面的代码就是死循环……
我是用下面这个代码研究返回值的
#include<stdio.h>
#include<stdlib.h>
int main(void)
{
int a;
int b;
int c;
printf("请输入三个整数\n");
int x=scanf("%d%d%d",&a,&b,&c);
printf("a=%d\nb=%d\nc=%d\n返回值=%d\n",a,b,c,x);
system("pause");
return 0;
}
别问我为什么不用上面AC的代码修改,我不会TAT,求大佬教我啊
经过以上研究,代码改成下面这样也可以AC了,反正题干一组两个整数,顺便解决了输入非数字会造成死循环的问题……
#include<stdio.h>
int main()
{
int a,b;
while(scanf("%d%d",&a,&b)==2)
{
printf("%d\n",a+b);
}
return 0;
}
其他人的AC代码还有写成这样的
就是把
while(scanf("%d %d",&a,&b)!=EOF)
改成
while(~scanf("%d %d",&a,&b))
没有丧偶的博文while(~scanf("%d %d",&a,&b))和while(scanf("%d %d",&a,&b)!=EOF)
原来他也改成scanf("%d %d",&a,&b)==2了……不过我真的是自己想出来的
【解释】while(~scanf("%d", &n))的~的含义
“~”意为取一个数的二进制反码。
while里不加判断条件默认为语句不等于0……
那么就是说取反后不等于0就进行循环
当scanf()读到文件结束,返回值为-1。
按教材写的“正数的补码、反码都是其本身
负数取反:原码的符号位不变,其他位按位取反”。
(-1)10原码(10000001)2取反后为八位二进制数 (11111110)2?并没有看出来这个是0
于是机智的我又写了一段程序
#include<stdio.h>
int main(void)
{
int A=-1;
int B=999;
B=~A;
printf("%d",B);
return 0;
}
输出结果为0……我先去哭一会……
才知道二进制数在内存中是以补码的形式存放的,-1原码即为:
(1111,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0001)2
反码:
(1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1110)2
补码:
(1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111,1111)2
按位取反:
(0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000)2
所以-1取反为0
………………………………于是下面这段可以不看了………………………………
0 的机器骂(原码):0|0000000000000000000000000000000
-1的机器码(补码):1|1111111111111111111111111111111
怎么又蹦出来个补码?1和0字符宽度不一样,没对齐强迫症忍耐一下……
来自于百度知道,没找到-1取反,先拿这个将就吧。和我们教材上写的根本不一样,教材说符号位不变……
………………………………于是上面这段可以不看了………………………………
所以while(~scanf("%d %d",&a,&b))与while(scanf("%d %d",&a,&b)!=EOF)等价
都是在scanf()返回值为-1时跳出循环
//…………………………分割线…………………………
累啊~~~问题还有很多(还是缓冲区不懂),取反不会,先在这里记着吧,不写下来怕忘了