操作符详解

目录

1.移位操作符

2.位操作符

1.移位操作符

<<左移操作符:左边抛弃、右边补0

>>右移操作符:分两种情况

1:逻辑移位:左边用0填充,右边丢弃

2:算术移位:左边用原该值的符号位填充,右边丢弃

注:移位操作符的操作数只能是整数,移位操作符是对2进制位进行操作移动

给出以下代码示例:

#include<stdio.h>

int main(void)
{
	//a的二进制原码 反码 补码:
	//00000000000000000000000000001010
	int a = 10;
	//  <<:左边抛弃,右边补0
	//00000000000000000000000000010100
	//所以b=20
	int b = a <<1;
	//  >>:左边用原来该值的符号位填充,右边丢弃
	//00000000000000000000000000000101
	//所以c=5
	int c = a >> 1;
	printf("%d\n%d\n%d", a, b, c);
	return 0;
}

    a的二进制原码 反码 补码:00000000000000000000000000001010

    <<:左边抛弃,右边补0
    00000000000000000000000000010100
    所以b=20

    >>:左边用原来该值的符号位填充,右边丢弃
    00000000000000000000000000000101
    所以c=5

我们来运行一下程序

警告⚠ :
对于移位运算符,不要移动负数位,这个是标准未定义的。
例如:
int num = 10;
num>>-1;//error

2.位操作符

& :按位与,对应二进制位上,有0则为0,两个同时为1才为1
|   :按位或,对应二进制位上,有1则为1,两个同时为0才为0
^  :按位异或,对应二进制位上,相同为0,相异为1
注:他们的操作数必须是整数。
对于按位与和按位或,这里有一个记忆的方法,比如在正常程序编写中,我们使用A&&B的话,必须要两个都为真才为真,一假全假,所以0可以看作假,1看作真,有一个0就为假,两个都是1就为真
给出以下代码示例:
#include <stdio.h>

int main(void)
{
	int num1 = 1;
	//00000000000000000000000000000001
	int num2 = 2;
	//00000000000000000000000000000010
	printf("%d\n",num1 & num2);
	//00000000000000000000000000000000
	printf("%d\n", num1 | num2);
	//00000000000000000000000000000011
	printf("%d\n", num1 ^ num2);
	//00000000000000000000000000000011
	return 0;
}

num1的补码为:00000000000000000000000000000001

num2的补码为:00000000000000000000000000000010

因此printf打印的结果应该为:

0

3

3

运行结果:

接下来又一道面试题: 不使用临时变量交换两个数的值

对于交换两个变量我们最常用的思路就是创建一个临时变量

int tmp=a;

a=b;

b=tmp;

即可完成交换

但本题有限制要求,不能创建临时变量

思路2:

int a=3,b=7;

a=a+b;//10

b=a-b;//3

a=a-b;//7

但这个也有缺陷,那就是当数字很大的时候int会爆掉

思路3:

利用按位异或操作符

先看一个例子:

#include<stdio.h>

int main(void)
{
	int a = 10;
	//00000000000000000000000000001010
	int b = 3;
	//00000000000000000000000000000011
	int c = a ^ a;
	//00000000000000000000000000001010
	//00000000000000000000000000001010
	//异或结果:00000000000000000000000000000000
	int d = a ^ a ^ b;
	//a^a的结果为0    0^b结果为b
	int e = a ^ b ^ a;
	//a^b 00000000000000000000000000001001
	//再^a得到00000000000000000000000000000011
	//发现结果还是为3
	printf("%d\n%d\n%d\n", c, d, e);
	return 0;
}

输出结果为:

 由此可以得到:异或运算符支持交换律

有了这个概念那么对下面的代码应该就更好理解了:
#include <stdio.h>
int main()
{
 int a = 10;
 int b = 20;
 a = a^b;
 b = a^b;//a^b^b = a
 a = a^b;//a^a^b = b
 printf("a = %d b = %d\n", a, b);
 return 0;
}

我们再看一道面试题:求一个整数存储在内存中的二进制中1的个数。

方法一:
最粗暴的方法,直接用循环把二进制表达式算出来,然后再逐个统计1的个数
#include <stdio.h>
int main()
{
	unsigned int num = -10;
	int count = 0;//计数
	while (num)
	{
		if (num % 2 == 1)
			count++;
		num = num / 2;
	}
	printf("二进制中1的个数 = %d\n", count);
	return 0;
}

这里num的数据类型使用unsigned int 的原因为当num为负数的时候就算不出来了

方法二:

利用按位与操作符

 当我们要判断这个二进制位的某一位是否为1,可以构造出一个对应位上为1,其他位全为0的二进制序列,利用按位与操作符的性质(&),都为1才为1可以得到该位置是否为1

那么如何构造呢?,我们知道1的二进制序列为:00000000000000000000000000000001,当我们想要将这个1设置在固定的某一项的时候,可以将其二进制序列进行左移(左边抛弃,右边补0)

那么代码可以这样写:

#include<stdio.h>

int main(void)
{
	int num = 10,i=0,count=0;
	for (int i = 0; i < 32; i++)
	{
		if (num & (1 << i))
		{
			count++;
		}
	}
	printf("二进制中1的个数为:%d", count);
	return 0;
}

但这样写的代码会有一个问题,那就是对于所有的二进制数都要遍历32次,比较麻烦

方法3:

#include <stdio.h>
int main()
{
	int num = 10;
	int i = 0;
	int count = 0;//计数
	while (num)
	{
		count++;
		num = num & (num - 1);
	}
	printf("二进制中1的个数 = %d\n", count);
	return 0;
}
//num:
//00000000000000000000000000001010
//num-1:
//00000000000000000000000000001001
//num&num-1:
//00000000000000000000000000001000
//num:
//00000000000000000000000000001000
//num-1:
//00000000000000000000000000000111
//num&num-1:
//00000000000000000000000000000000

每一次num&num-1都会借走一个1,当num为0的时候结束循环

运行结果:

练习题:获取一个整数二进制序列中所有的偶数位和奇数位,分别打印出二进制序列

有了上一题的经验,我们知道如何拿到一个数的二进制的某一个的值,那么这道题就好写很多了
#include<stdio.h>

int main(void)
{
	int n = -1;
	printf("奇数位:");
	for (int i = 30; i >= 0; i -= 2)
	{
		printf("%d ", (n >> i) & 1);
	}
	printf("\n");
	printf("偶数位:");
	for (int i = 31; i >= 1; i -= 2)
	{
		printf("%d ", (n >> i) & 1);
	}
	return 0;
}

练习题:

编程实现:两个int(32位)整数m和n的二进制表达中,有多少个位(bit)不同? 

输入例子:

1999 2299

输出例子:7

这题的思路很明显,可以用位操作符^(按位异或)(相同为0,相异位1)

那么只需要计算1999^2299的结果有多少个1就行了

代码:

#include<stdio.h>

int main(void)
{
	int a = 1999, b = 2299;
	int tmp = a ^ b,count=0;
	while (tmp)
	{
		tmp = tmp & (tmp - 1);
		count++;
	}
	printf("%d", count);
	return 0;
}

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值