【C语言】移位操作符 &位操作符 - 对二进制位进行精准操作【+面试题目】_[初阶篇]

快速导航

【前言】

1.移位操作符

1.1左移操作符(<<)

1.2右移操作符(>>)

2.位操作符

2.1 & 按位与

2.2  | (按位或) 

2.3  ^ (按位异或)

3.面试题目

3.1 交换两个变量(不创建临时变量)

3.2统计二进制中1的个数 

3.2.1 方法一:右移(>>)和按位与(&)

3.2.2 方法二:使用取余操作符(%)

3.2.3 方法三:借助num&(num-1)​​​​​​​

【前言】

相信有很多人对移位操作符和位操作符并不是很理解,没有关系,认真读完本篇文章,你对C操作符的理解会上升到一个新高度。

虽然说本篇文章是初阶篇,但是文章内容并不简单,操作的时候涉及到二进制位,那我们就先来看一看何为二进制位?

二进制位简称“位”,是二进制记数系统中表示小于2的整数的符号,一般用1或 0表示,是具有相等概率的两种状态中的一种。

二进制位的位数可表示一个机器字的字长,一个二进制位包含的信息量称为 - 比特。

1.移位操作符

移位操作符有两种:一种是左移操作符(<<),另一种是右移操作符(>>)

这两种操作符都是对整数在存储在电脑中的二进制位进行操作(注意:移位操作符的操作数必须是整数)。

1.1左移操作符(<<)

接下来我们借助一个整数来更好的理解和应用左移操作符:

 watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQ2F0enp6NjY2,size_18,color_FFFFFF,t_70,g_se,x_16

在计算机内存中存储的是二进制形式的补码,而正数的原码,反码,补码相同,5在内存中的补码:

 watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQ2F0enp6NjY2,size_19,color_FFFFFF,t_70,g_se,x_16

移位操作符,移动的是二进制位,因为整数在内存中存储的是补码,所以移动的是内存中存储的补码 。

补码我们已经给出,接下来看一看移位操作符到底是怎么进行移位呢?

左移操作符移位原则:左边抛弃,右边补0。

#include <stdio.h>

int main()
{
    int a = 5;
    printf("%d\n", a << 1);
    return 0;
}

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQ2F0enp6NjY2,size_20,color_FFFFFF,t_70,g_se,x_16

5左移之后结果为10,看似是有乘2的效果的,那么是不是这样的呢?

下面我们来多举几个栗子验证一下。

#include <stdio.h>
int main()
{
	int a = -1;
	printf("%d\n", a << 1);
	
	a = -10;
	printf("%d\n", a << 1);

	a = 100;
	printf("%d\n", a << 1);
	return 0;
}

负数左移的效果也是一样的(以-1为例):

结论:左移操作符确实有乘2的效果。  

练习使用一下左移操作符:

原题链接:2的n次方计算_牛客题霸_牛客网 

题目描述:不使用累加法的基础上,使用左移操作符(<<) 完成2的n次方的计算。

 代码实现

#include <stdio.h>

int main()
{
    int n = 0;
    scanf("%d", &n);
    printf("%d\n", 1 << n);
    return 0;
}

1.2右移操作符(>>)

右移操作符和左移操作符是相似的,右移操作符和左移操作符最大的区别是在右移之后:

1.左边补符号位(算术右移)

2.左边补0(逻辑右移)

究竟是哪一种取决于程序的运行环境,不同编译器下右移方式可以不同。

int main()
{
	int a = -1;
	printf("%d\n", a >> 1);
	return 0;
}

上面是VS2019下的运行结果,VS2019支持的是算术右移。 

 注意:移位操作符,不要移动负数位,这是标准未定义的;

​​​​​​​对比一下左移操作符乘2效果,右移操作符是否具有除2的效果呢?

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQ2F0enp6NjY2,size_20,color_FFFFFF,t_70,g_se,x_16

对于正数来说,可以认为具有除2的效果,但是不要忘了负数;我们在上面举例的-1右移之后还是-1,就不满足了。 

所以不能直接说右移操作符具有除2的效果。​​​​​​​

2.位操作符

位操作符,是对一个数的二进制位进行操作,两个操作数,且操作数必须是整数。

具体分为三种:& (按位与)     |(按位或)     ^(按位异或)。计算机中位运算操作,均是以二进制补码形式进行的

2.1 & 按位与

两个数的二进制相同位同为1时结果为1,否则为0。

下面看一下使用按位与(&)操作的两种情况 :

2.2  | (按位或) 

 两个数的相同二进制位同为0时结果为0,否则为1。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQ2F0enp6NjY2,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQ2F0enp6NjY2,size_20,color_FFFFFF,t_70,g_se,x_16

2.3  ^ (按位异或)

两个数相同二进制位相异时为1,相同是为0。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQ2F0enp6NjY2,size_20,color_FFFFFF,t_70,g_se,x_16 watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQ2F0enp6NjY2,size_20,color_FFFFFF,t_70,g_se,x_16

3.面试题目

3.1 交换两个变量(不创建临时变量)

在交换两个变量时,我们经常会借助第三个变量tmp;

比如交换a和b的值:

int tmp = a;

a = b;

b = tmp;//那么不创建临时变量的话我们怎么来交换两个变量呢?

使用异或操作符(^),异或的两个特征:0^num = num;num^ num = 0;

 代码实现

int main()
{
    int a = 10;
    int b = 20;
    printf("a=%d, b=%d\n", a, b);
    a = a ^ b;
    b = a ^ b;//b修改为a
    a = a ^ b;//a修改为b
    printf("a=%d, b=%d\n", a, b);
    return 0;
}

缺陷:因为按位异或操作符的操作数只能是整数,所以交换的两个变量也必须是整数,只能完成两个整数的交换,无法完成两个浮点数的交换。 

3.2统计二进制中1的个数 

3.2.1 方法一:右移(>>)和按位与(&)

代码实现:

int getBinaryCount(int num)
{
	int count = 0;//记录二进制中1的个数
	int i = 0;
	for (i = 0; i < 32; i++)
	{
		if (((num >> i) & 1) == 1)
		{
			count++;
		}
	}
	return count;
}

3.2.2 方法二:使用取余操作符(%)

一个十进制的数,想要获取它的每一位,需要进行%10、/10;二进制的数也是一样的,可以通过%2、/2来获取每一位。

代码实现 

int getBinaryCount(unsigned int num)
{
	int count = 0;
	while (num)
	{
		if(num % 2 == 1)
			count++;
		num /= 2;
	}
	return count;
}

这里解释一下为什么要传入unsigned int类型:使用负数举例,如果num是-1的话,进入循环一次之后除2就变为0,无法得到二进制中1的正确个数;

使用unsigned int的话会把-1的补码当成一个正数的补码,这是一个很大的数,可以进行以上操作。

3.2.3 方法三:借助num&(num-1)

代码实现 

int getBinaryCount(int num)
{
	int count = 0;
	while (num)
	{
		num &= num - 1;
		count++;
	}
	return count;
}
评论 38
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

new出新对象

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值