在今天的快乐刷题中,我发现一位大佬的解法非常有意思,让我们先看看题目:
显而易见,需要我们使用scanf的返回值来进行循环的控制。点此跳转:关于scanf返回值的前情提要
while (scanf("%d", &t) == 1){}
这个基于这个循环模块,我们可以很轻松的完成题目的要求。
#include <stdio.h>
int main() {
int t;
while (scanf("%d", &t) == 1) {
if(t > 0) printf("1\n");
else if(t < 0)printf("0\n");
else printf("0.5\n");
}
return 0;
}
秉持着人外有人,天外有天的原则,我点开题解,去寻找更 牛逼 高级 的解法。
榜一大佬的代码是这样的:
#include<stdio.h>
main()
{
int t;
while(~scanf("%d\n",&t))
{
if(t>0)
printf("1\n");
else if(t==0)
printf("0.5\n");
else
printf("0\n");
}
}
不难发现,他与我的代码高度相似,除了一个部分:
while(~scanf("%d\n",&t))
这是啥?刚刚看到的时候我一脸懵逼。
我们知道,‘~’在c语言中的作用是按位取反,但while的接受的是布尔值啊?取反不应该使用逻辑取反符号‘!’吗?
不对不对,这里一定另有玄机。
众所周知:scanf返回值是成功实际接受到的参数数量,此时,我们只用scanf接收了一个参数,那么 scanf的返回值始终 <= 1。
这也就是这个语句的关键!
我们可以列出scanf返回值的所有可能情况: 当scanf正确接收了一个参数,返回1; 当scanf读取错误,返回EOF; 当scanf接收到文件结束符,返回EOF;
没错!scanf只会有两种可能的返回值! EOF的值是什么?在大部分的情况下是-1。
即scanf的返回值是1或者-1。
那么,接下来思路就清晰了,观察按位取反符‘~’的作用:
在计算机中,整数通常使用补码(two’s complement)形式来表示负数。对于-1的真值,即其补码表示,如下:
对于一个8位整数(一个字节),-1的补码表示是11111111。
对于一个16位整数,-1的补码表示是1111111111111111。
对于一个32位整数,-1的补码表示是11111111 11111111 11111111 11111111。
对于一个64位整数,-1的补码表示是1111111111111111 1111111111111111 1111111111111111 1111111111111111。
简而言之,-1的真值(补码表示)就是所有位都是1的二进制数。 那么,-1按位取反的结果是什么呢?
没错,就是0。
0就是False,就是假,就是结束循环!
至于1按位取反,得到的是非0值,也就是真!
当返回值只有-1和1时,我们可以采用按位取反符‘~’简化代码,提高逼格。
while(~scanf("%d\n",&t))
这个循环的应用场景通常包括:
需要注意的是,这个循环在读取失败时会立即结束,因此在使用时应该考虑到错误处理和用户输入验证的问题。此外,scanf
函数在读取失败时不会从输入流中消耗非整数字符,这可能会导致后续的 scanf
调用再次失败,因此在实际应用中可能需要额外的逻辑来处理这种情况。