C:关于位操作符:&、|、^、~的一些应用

一些用来熟悉位操作符的应用

一、按位异或:^

异或运算:相同为0,相异为1

应用:在不引入临时变量(第三变量)的情况下,实现两个整数的交换。

关于两个整数交换,我们有一些方法,比如说,创建一个第三变量,就可以很轻易的实现两个整数的交换,如下代码:

#include <stdio.h>
int main()
{
	int a = 10;
	int b = 20;
	printf("交换前:a=%d b=%d\n", a, b);
	int c = a;
	a = b;
	b = c;
	printf("交换后:a=%d b=%d\n", a, b);
	return 0;
}

但是,该程序引用了第三个变量,如果不引入第三个变量,我们又有什么办法来实现两个整数的交换呢?

这里我们就可以使用按位异或操作符^来达到想要的目的。

代码展示:

#include <stdio.h>
int main()
{
	int a = 10;
	int b = 20;
	printf("交换前:a=%d b=%d\n", a, b);
	a = a ^ b;
	b = a ^ b;
	a = a ^ b;
	printf("交换后:a=%d b=%d\n", a, b);
	return 0;
}

相信你看到这个程序可能会有一点懵并充满疑惑,这是怎么实现的?

在解析这串代码之前,我们需要了解一些知识来为读懂代码做准备。

异或运算:相同为0,相异为1

int a =3;

int b = 5;

a的二进制表示:011

b的二进制表示:101

1. a^a = 0

a = 011

a = 011

a^a = 000

我们可以知道,整数和它自己本身异或得到的结果是0

2. a^0 = a

a = 011

0 = 000

a^0 = 011

我们可以得到,整数和0异或得到的结果是整数本身

当我们知道这些信息后,我们就可以解析这串代码了

a = a ^ b;
b = a ^ b;
a = a ^ b;

 开始时,将a ^ b的值赋给a,因此,b = a ^ b表达式中的a的值就变为a ^ b,通过异或运算,我们可以得到b=a,这时候,b的值就变为a了,但是a的值没有变化,还是 a ^ b,因此,在a = a ^ b表达式中, a ^ b中a的值还是a ^ b,b的值变为了a,通过异或运算,我们可以得到 a=b。

下面是图解:

图片或许表达的不是很清楚,如果有不明白的,可以私我,欢迎!

二、按位与:&

与运算:有0为0,全1为1

应用:求一个整数存储在内存中的二进制中1的个数

法一:通过判断整数的最后一位

int n = 15;  
int count = 0;//二进制中1的个数

将15与1进行 与运算 15&1

00000000000000000000000000001111   //15的二进制表示
00000000000000000000000000000001  // 1的二进制表示
00000000000000000000000000000001  //与运算结果
通过与运算结果是1,我们可以判断出15的最低位是1

因此,如果想得到n的二进制最低位,我们就可以给n按位与上一个1,通过判断结果是0还是1来确定n的二进制最低位是什么。

当我们得到最后一位后,如果结果是1的话,我们就count++,该最低位统计过后,我们需要统计倒数第二位,该怎么办呢?

我们可以通过右移操作符 >> 向右移动一位,这样就可以丢掉已经统计过的最低位,这样倒数第二位就来到了最低位,然后再按位与1,判断结果,如果结果是1,就count++,如果结果是0,则count的值不变,重复操作32次后,我们就可以判断完每一位是否为1,从而得到整数存储在内存中的二进制中1的个数。

for (int i = 0; i < 32; i++)//一个整型是4个字节,一个字节8个bit,这里的32就是32个bit位
	{
		if (((n >> i) & 1) == 1)
			count++;
	}

这段代码使用一个循环来检查整数 n 的二进制表示中值为 1 的位的数量。 具体来说,循环从 0 迭代到 31 。对于每次迭代 i ,首先将 n 向右移动 i 位,然后与 1 进行按位与操作。如果结果为 1 ,说明 n 右移 i 位后的最低位是 1 ,此时就将计数器 count 的值增加 1 。当循环结束时,count 中存储的就是 n 的二进制表示中 1 的个数。

完整代码:

#include <stdio.h>
int main()
{
	int n = 0;
    scanf("%d",&n);
	int count = 0;//二进制中1的个数
	for (int i = 0; i < 32; i++)//一个整型是4个字节,一个字节8个bit,这里的32就是32个bit位
	{
		if (((n >> i) & 1) == 1)
			count++;
	}
	printf("%d\n", count);
	return 0;
}

从上面代码,我们可以发现一些问题,就是不管所求数的二进制中有几个1,都需要循环32次

我们可以修改一下

法二:

int n = 13

表达式n = n & (n-1)

13的二进制序列:1101

n = n-1
第一组n和n-1
1101 --n
1100 --n-1
1100 --新的n
将新的n与原来相比,可以看到少了一个1,且是最后一位
第二组n和n-1
1100 --新的n
1011 --n-1
1000 --新的n
与第二个n相比,可以看到最右边的1又没了
第三组n和n-1
1000 --新的n
0111 --n-1
0000 --新的n
与上一个n对比,1又消去了。

从上面的例子,我们应该也能看出表达式n = n & (n-1)的作用:让n的二进制序列中最右边的1消失

n = n & (n-1)表达式每执行一次,就会去掉一个1,知道n中的1全部被去掉为止,因此,我们可以通过表达式进行的次数,来计算n二进制序列中有几个1

代码展示:

#include <stdio.h>
int main()
{
	int n = 0;
    scanf("%d",&n);
	int count = 0;//二进制中1的个数
	while(n){
      n = n & (n-1);
      count++;}  
	printf("%d\n", count);
	return 0;
}

该程序的好处是不会产生额外的循环,n的二进制序列中有几个1,就循环几次,没有就不循环。

 

三、按位或:| 按位取反:~

或运算:有1为1,全0为0

应用:将13的二进制序列的第5位修改位1,然后再改回0

13的二进制序列:00000000000000000000000000001101
将第5位置改为1:00000000000000000000000000011101
再将第5位改回0 :00000000000000000000000000001101

00000000000000000000000000001101
00000000000000000000000000010000
或结果:
00000000000000000000000000011101

那么00000000000000000000000000010000该怎么得到呢?

我们可以将1的二进制序列通过左移操作符向左移动4位 (1<<4)

这样就可以得到想要的结果了

代码展示:

#include <stdio.h>
int main()
{
	int n = 13;
	n |= (1 << (5-1));//将第5位0改为1
	printf("%d\n", n);	
	return 0;
}

那么我们该怎么改回去呢?

这里我们就要用到&和~了

因此,代码展示:

#include <stdio.h>
int main()
{
	int n = 13;
	n |= (1 << (5-1));//将第5位0改为1
	printf("%d\n", n);	//29
	n &= (~(1 << (5 - 1)));//将第5位改回来
    printf("%d\n", n);//13
	return 0;
}


本篇文章到这里就结束了,期待你们的下次到来!!!

评论 36
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值