C语言操作符详解

一.原码、反码、补码

整数的二进制表示方法分三种,即原码、反码、补码。

有符号整数的三种表示方法均由两部分组成:符号位+数值位。最左边一位1表示负数,0表示正数

正数的原反补码相同;

负数的原反补各不相同:

原码:直接将数值按照正负数形式翻译成二进制。如-1的原码为100000000000000000000001;

反码:将原码除了符号位,全部取反。-1的反码:11111111111111111111111111111110;

补码:反码+1为补码。-1的补码为:11111111111111111111111111111111;

简言之,三者关系为:

二.移位操作符

>>右移操作符  <<左移操作符

注意:移动的是二进制位,且操作数只能是整数!!

2.1 左移操作符

左边移出一位,右边补0;

例如下面代码演示:

#include <stdio.h>
int main()
{
    int a=5;
    int b=(a<<1);
    printf("b=%d\n",b);
    printf("a=%d\n",a);
    return 0;
}

具体操作步骤为:a为整型,4个字节,32个bit位

运算结果为:

可看到a经过运算并没有改变它原本的值,这一点需要注意!若要改变则a经过运算后赋值给自己,即复合赋值,写为a<<=1。

2.2 右移操作符

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

  1. 逻辑右移:右边移出一位(丢弃),左边补0
  2. 算数右移:右边丢弃,左边补上原该值符号位 

所以右移究竟采用哪一种,取决于编译器的实现,常见数编译器采用算术右移,更加合理。

注意:移位不要移动负数位,这是标准未定义的。

如:-1 在内存中的补码为11111111111111111111111111111111

逻辑右移后补码是 01111111111111111111111111111111(正数)(右边丢弃,左边补0)

取反                      01111111111111111111111111111111

原码                      01111111111111111111111111111111

算术右移               11111111111111111111111111111111  -1(左边补1,右边丢弃)

三.位操作符

位操作符有:

1.&    //逻辑按位与

2.|     //逻辑按位或

3.^    //按位异或

4.~    //按位取反

注意:它们的操作数必须整数

3.1 & 逻辑-按位与

二个二进制数对每一位进行比较,一个为0,则该位置为0;两个都为1,该位置为1;

例如:1的二进制数的补码是 00000000000000000000000000000001

           3的二进制数的补码是 00000000000000000000000000000011

则1&3的二进制数的补码是    00000000000000000000000000000001

利用&的“遇到0就是0”功能,可轻松将二进制中某一位由1变0;或者判断该位数是否为1;

例题:计算某位数的二进制中1的个数?

求1的个数就要知道每一位都是什么,我们知道在十进制中求每一位是用n%10和n/10循环使用 ,类比下来是不是用n%2和n/2就能知道n的二进制数的每一位呢?

3.1.1方法一

如13的二进制数 00000000000000000000000000001101

13%2=1 13/2=6

6%2=  6/2=3

3%2=1    3/2=1

1%2=   1/2=0(停止)

我们发现这样的循环确实可以实现统计二进制中1的个数,每到n%2=1时就1的个数就+1,,由此代码如下:

#include <stdio.h>
int main()
{
	int n = 0; int count = 0;
	scanf("%d", &n);
	while (n)
	{
		if (n % 2 == 1)
			count++;
		n /= 2;
	}
	printf("%d\n", count);
	return 0;
}

但是当我们把负数带进去,结果就不是预想的那样: 我们知道-1的补码里有32个1,可在该代码结果却是0,这是负数%2还是负数,无法使得count变化。

 

3.1.2 方法二

想办法使编译器将负数认成“正数”,当我把n的类型变成无符号整数(unsigned int)就很好解决这一问题,即便我输入负数,编译器就不会受符号影响,相当于把符号位变成了数值位,但数字不变。

#include <stdio.h>
int main()
{
    unsinged int n=0;int count=0;
    while(n)
    {
        if(n%2==1)
            count++;
        n/=2;
    }
    printf("%d/n",count);

    return 0;
}

3.1.3 方法三

使用n=n&(n-1)算法,该算法可使二进制中最右边的1去掉

 如n=13 简化一下它的二进制 n=1101    n-1=1100    n=n&(n-1)=1100

                                               n=1100    n-1=1011    n=n&(n-1)=1000

                                               n=1000    n-1=0111    n=n$(n-1)=0000

                                               n=0000

由此可知代码如下:

 

#include <stdio.h>
int main()
{
	int n = 0; int count = 0;
	scanf("%d", &n);
	while (n)
	{
		n = n & (n - 1);//这个表达式能将二进制中最右边的1去掉
		count++;
	}
	printf("%d\n", count);
	return 0;
}

 

3.2 | 逻辑-按位或

二个二进制数对每一位进行比较,一个为1,则该位置为1;两个都为0,该位置为0;

利用|的“遇到1就是1”功能,可轻松将二进制中某一位由0变1.

3.3 ~取反

对二进制数进行每一位取反,包括符号位,1取反为0,0取反为1

例题:将13二进制数的第五位改成1 再改成0

13的二进制数 00000000000000000000000000001101

由0变1,用|,且保障其他位不变

则用                00000000000000000000000000010000 去和该数进行逻辑或 而这个数是1<<4而来

在由1变0,用&,且保障其他位不变

   改完之后      00000000000000000000000000011101

则用                1111111111111111111111111111111101111去和改之后的数去进行逻辑与

而该数是对1<<4取反

代码如下:

#include <stdio.h>
int main()
{
	//改1
	int n = 13;
	n |= (1 << 4);//要把n的值改了
	printf("%d\n", n);
	//改0
	//13 00000000000000000000000000001101
	//29 00000000000000000000000000011101
//按位与 11111111111111111111111111101111
	//该数对1<<4取反
	n &= ~(1 << 4);
	printf("%d\n", n);
    return 0;
}

 

 3.4 ^按位异或

两个二进制数每一位相比,相同为0,不同为1;

按此规律,n^n=0,0^n=n

 例题:不要创建临时变量,将a,b交换数值

  

​
#include <stdio.h>
int main()
{
    int a=3,b=5;
    printf("之前a=%d,b=%d\n",a,b);
    a=a^b;//将其看作一把钥匙,求谁带谁
    b=a^b;//b=a^b^b,b^b=0,a^0=a
    a=a^b;//a=a^b^a,a^a=0,b^0=a
    printf("现在a=%d,b=%d\n",a,b);
    return 0;
}

​

 

四、逗号表达式

遵循从左到右依次计算的原则,整个表达式结果是最后一个表达式的结果

五、下标访问[],函数调用()

5.1数组访问[]

操作数:一个数组名+一个索引值

int arr[]={1,2,3,4}//创建数组并初始化
arr[2]=3//对数组进行下表访问
//[]的两个操作数是arr和2

5.2函数调用

操作数:一个函数名+传给函数的参数

#include <stdio.h>
void greet()
{
    printf("Hello World!")
}
int main()
{
    greet()//这里的()就是函数调用操作符
    return 0;
}

持续更新中……

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值