sizeof()的坑🕳

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
int i;
int main()
{
i--;
if (i > sizeof(i))
{
printf(">\n");
}
else
{
printf("<\n");
}
return 0;
}

观察上端代码,思考一下输出结果是什么?

首先定义了一个全局变量,全局变量没有赋值,默认值为0;然后i–;i变成了-1.你也许会说sizeof(-1),-1是int类型的,占4个字节,-1<4,结果不就是<吗!其实不然,结果是>,-1大于4?数学是体育老师教的!

原因在于sizeof()的返回值是无符号整型,也就是unsigned int,两数比较时,编译器会将左侧的值也转换成无符号整数,-1在内存中存储的是全1,即11111111111111111111111111111111,无符号嘛,会认为这是一个很大的数,所以最后输出了>.

所以当一个数与sizeof()直接比较时,就要小心咯,可能会有意想不到的结果。

运算符优先级

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
int main()
{
int a, b, c;
a = 5;
c = ++a;
b = ++c, c++, ++a, a++;
b += a++ + c;
printf("a = %d b = %d c = %d\n:", a, b, c);
return 0;
}

观察上段代码,输出结果是什么?很烦这种代码,虽然没什么意义,但既然错了,还是记录下吧。主要考察操作符的优先级和结合性。主要说两点,一是逗号表达式的优先级最低,所以b= ++c , c++ , ++a , a++;先算b=++a,然后再算逗号后面的操作。二是+=操作符的优先级也很低,所以在b += a++ + c中先计算a++ +c,再将结果加上b后赋值给b。

image-20220306211323371

二进制中1的个数

求二进制中1的个数,有很多方法。

方法一:利用按位与&和移位>>运算符。一个数按位与&1,可以求得这个数二进制的最低位。只求最低位哪行啊,我要的是所有位上1的个数,结合移位运算符,(n>>1)&1,得到的就是第二位,(n>>2)&1,得到的就是第三位,一直到31,得到一次加一次,就得到了二进制中所有的1.

1
2
3
4
5
6
7
8
9
10
11
int main()
{
int n = 0;
int i = 0;
int count = 0;
scanf("%d",&n);
for (i = 0; i < 32; i++) {
if ((n >> i) & 1) count++;
}
printf("%d", count);
}

方法二:利用%和/运算符,比如1987,1987%10,得到了后一位7,1987/10%10,得到了8,1987/100%10,得到了9,1987%1000/10,得到了1。十进制/10%10,二进制自然就/2%2。值得注意的是数的类型要定义为unsigned int,否则该方法只适用于正整数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int main()
{
int n = 0;
scanf("%d", &n);
int count = 0;
unsigned int tmp = n;
while (tmp) {

if (tmp % 2) {
count++;
}
tmp = tmp / 2;

}
printf("%d", count);
}

方法三:利用表达式n=n&(n-1),计算表达式执行的次数,n为0时结束循环。如下图所示:

image-20220307103014897

1
2
3
4
5
6
7
8
9
10
11
int main()
{
int n = 0;
scanf("%d", &n);
int count = 0;
while (n) {
n = n & (n - 1);
count++;
}
printf("%d", count);
}

两个数二进制不同位的个数

有了上道题的基础,这道题就迎刃而解了。

思路一:默认最低位是第0位,n>>i&1可以求得第i位的二进制数,如果两数不等,计数器加一即可。

1
2
3
4
5
6
7
8
9
10
11
12
int main()
{
int a = 0;
int b = 0;
scanf("%d %d", &a, &b);
int i = 0;
int count = 0;
for (i = 0; i < 32; i++) {
if ((a >> i & 1) != (b >> i & 1)) count++;
}
printf("%d", count);
}

思路二:利用异或^运算符,两数异或,相同位为0,不同位为1。对异或后的数求二进制中1的个数,便得到了二进制中不同位的个数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int main()
{
int a = 0;
int b = 0;
scanf_s("%d %d", &a, &b);
//1.两数异或
int c = a ^ b;
int count = 0;
//2.求二进制中1d
while (c) {
c = c & (c - 1);
count++;
}
printf("%d", count);
}