C语言操作符详解(一)

一、原码,反码,补码

   在正式介绍操作符之前,我想在这里先介绍一下原码,反码,补码的概念以及他们之间的转换,这对于我们今天的介绍有很大帮助。还有一点是我们今天只介绍整型的概念。

 1.概念

   整数的2进制表示方法有三种,即原码、反码和补码。

   有符号整数的三种表示方法均有符号位和数值位两部分,2进制序列中,总共32个比特位,最⾼位的1位是被当做符号位,剩余的都是数值位。 符号位都是用0表示“正”,⽤1表示“负”。

如:0的原码为00000000000000000000000000000000(总共32个比特位)

      -1的原码为10000000000000000000000000000001

其中正整数的原、反、补码都相同。 负整数的三种表示方法各不相同。

(1)原码:直接将数值按照正负数的形式翻译成⼆进制得到的就是原码。

(2)反码:将原码进行取反操作得到反码,1变为0,0变为1。其中第一位的符号位不变

(3)补码:将反码+1得到补码,(注意满2进1)

注:原码取反加1得到补码,而补码也可直接取反加1得到原码。 

对于整型来说,存储在内存中的都是以补码的形式存储,同时之后的计算也都是补码之间的计算,然后在变为原码,所以在这里也提醒大家不要搞混了,导致计算错误,操作失误。

二、操作符

1.移位操作符

(只能是整数且移动的是存储在内存中的二进制位,也就是补码)

   移位操作符包括左移操作符(<<),右移操作符(>>)

 (1)规则:左移:向左移位,左边抛弃,右边补0(左移一位有乘2的效果)

int main()
{
	int a = 10;
	int b = a << 1;//具有*2的效果
	printf("%d\n", a);//10
	printf("%d\n", b);//20
	return 0;
}

                   右移:逻辑右移:左边用0填充,右边丢弃 ;算术右移:左边用原该值的符号填充,右边丢弃。采用哪种右移取决于编译器,但通常都是采用算术右移。(有除2的效果)

int main()
{
	int a = 10;
	int b = a >> 1;//具有/2的效果
	printf("%d\n", a);//10
	printf("%d\n", b);//5
	return 0;
}

警告⚠:移位操作符不要用于移动负数位。  

 2.位操作符

    位操作符:&,|,^, ~

    &叫按位与,规则:a和b对应计算有0则为0,2个同时为1才为1.

    |叫按位或,规则:a和b对应计算只要有1就是1,两个同时为0才为0.

    ^叫按位异或,规则:a和b对应计算相同为0才为0,相异为1.

   ~叫按位取反,规则:a和b对应计算1取反为0,0取反为1.

注意:以上操作符都是二进制操作符,都是通过补码计算,他们的操作数必须是整数,其中^支持交换律。

int main()
{
	int a = 3;
	int b = 5;
	int c = 8;
	int n = 3 ^ 5 ^ 8;//14
	int m = 3 ^ 8 ^ 5;//14
	printf("%d %d\n", n, m);
	return 0;
}

 一道思考题:不能创建临时变量(第三个变量)实现两个变量的交换。

//不创建其他变量,使两个变量的值交换。
/*方案一:使用第三变量好处是直观,清楚。缺点是只适用于部分数值*/
//int main()
//{
//	int a = 3;
//	int b = 5;
//	int c = 0;
//
//	c = a + b;
//	a = c - a;
//	b = c - b;
//	printf("变量a=%d\n", a);
//	printf("变量b=%d\n", b);
//	return 0;
//}


/*方案二:可任意处理多种数值,缺点是代码不直观*/
//int main()
//{
//	int a = 3;
//	int b = 5;
//	//异或支持交换律。
//	//011--3的原码;101--5的原码。
//	a = a ^ b;
//	b = a ^ b;
//	a = b ^ a;
//	printf("变量a=%d\n", a);
//	printf("变量b=%d\n", b);
//	return 0;
//}

3.练习 

接下来让我们将这些操作符综合起来来看一个题目吧!

1.编写一个代码,求一个整数储存在内存中二进制中1的个数。

方案一:采用循环的方式,因为一个数的原,补码总共各有32个比特位,所以很容易想到用循环的的方式进行。这里的n=n/2是将你自己输入的整数转化为二进制(可以去看我的文章:神奇的二进制),缺点:无法对有符号整数运算。

//方案一:
//int main()
//{
//	int n = 0;
//	int count = 0;
//	scanf("%d", &n);
//	while (n)
//	{
//		if (n % 2 == 1)
//			count++;
//		n = n/2;
//	}
//	printf("二进制位中一的个数为%d", count);
//	return 0;
//}

方案二:这里我们可以通过自定义一个函数来完成,并在传参的时候将函数中的形参改为unsigned int n

//方案二:num = -1,可实现对有无符号的整数运算
//int count_bite_one(unsigned int n)//将int改为unsigned int
//{
//	int count = 0;
//	while (n)
//	{
//		if ((n % 2) == 1)
//			count++;
//		n = n/2;
//	}
//	return count;
//}

//int main()
//{
//	int num = 0;
//	scanf("%d", &num);//-1会为0,此时%2会为0
//	int ret = count_bite_one(num);
//	
//	printf("1的个数为%d", ret);
//	return 0;
//}

方案三:我们通过前面的原,反,补码可知1的原码是000~001,在由&操作符可知n&1==1,我们可以用此表达式判断1的个数,只需将n>>i与1进行&操作,在配合循环通过循环次数判断1的个数。


//int count_bite_one(int n)
//{
//	int i = 0;
//	int count = 0;
//	for (i = 0; i < 32; i++)
//	{
//		if (((n >> i) & 1) == 1)//可实现有,无符号运算
//		{
//			count++;
//		}
//			
//	}
//	return count;
//}

//int main()
//{
//	int num = 0;
//	scanf("%d", &num);
//	int ret = count_bite_one(num);
//	printf("1的个数为%d", ret);
//	return 0;
//}

方案四:我们需要用到算法:n = n & (n-1)

              所以我们在这里进行讲解,在展示代码

//int count_bite_one(int n)
//{
//	int count = 0;
//	while(n)
//	{
//		n = n & (n - 1);//算法计算,多次循环后结果n为0,循环停止。
//		count++;
//	}
//	return count;
//}

//int main()
//{
//	int num = 0;
//	scanf("%d", &num);
//	int ret = count_bite_one(num);
//	printf("1的个数为%d", ret);
//	return 0;
//}

 2.写一个代码判断n是否为2的次方数(加强对算法的印象)

//int main()
//{
//	int n = 0;
//	scanf("%d", &n);
//	if (((n - 1) & n) == 0)
//	{
//		printf("yes");
//	}
//	return 0;
//}

3.编写代码将13二进制序列的第5位修改为1,再改回0

int main()
{
	int a = 13;
	//00000000000000000000000000001101 - a的原码也是补码,因为正数的原,反,补都一样。
	//00000000000000000000000000011101 - 将a的第5位修改为1
	//00000000000000000000000000010000 -该补码满足题意,而该补码可有1向左移动4位得到
	a = a | (1 << 4);//29
	printf("%d\n", a);

    //00000000000000000000000000011101 - 将其与1左移4位后的补码并取反的结果,进行按位与操作
	a = a & ~(1 << 4);
	printf("%d\n", a);//13
	return 0;
}

总结:我们发现二进制并没有我们想的这么简单,也是具有很多操作性的,所以我希望这篇博客能够帮助你,这里也希望大家熟练掌握n&(n-1)=n这个算法,最后希望大家多多支持!

  • 25
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值