常见操作符详解

1. 操作符的分类

  • 算术操作符: + , - , * , / , % 
  • 移位操作符: <<  >> 
  • 位操作符:  &  |  ^ 
  • 赋值操作符:  =  , += , *=  ,/=  , <<= , >>= , &= , |= , ^= 
  • 单目操作符: ! , ++ , --, & , * , + ,-  , ~ , sizeof ,(类型)
  • 关系操作符: > ,>= , < ,<= ,== , != 
  • 逻辑操作符:&& ,|| 
  • 条件操作符: ? :
  • 逗号表达式:
  • 下标引用: [ ] 
  • 函数调用: ()
  • 结构成员访问:. 、->

2.  二进制和进制转换

在日常生活和学习中我们早已听过数制的概念:

        数制也称为计数制,是一种计数的方法,是用一组固定的符号和统一的规则来表示数值的方法。在计数过程中采用进位的方法称为进位计数制(进制),包括数位、基数和位权三个要素。

数位:

        数位,指一个数中每一个数字所占的位置。整数部分的数位从右起,每4个数位是一级,个级包括个位、十位、百位和千位,表示多少个一;万级包括万位、十万位、百万位和千万位,表示多少个万;亿级包括亿位、十亿位、百亿位和千亿位,表示多少个亿……小数部分的数位从左往右依次为十分位、百分位、千分位……表示多少个十分之一、百分之一、千分之一……

基数:

        数制所使用数码的个数。例如,二进制的基数为2,十进制的基数为10。

位权:

        数制中某一位上的1所表示数值的大小(所处位置的价值)。例如,十进制的123,1的位权是100,2的位权是10,3的位权是1。二进制中的 1011 (一般从左向右开始),第一个1的位权是8,0的位权是4,第二个1的位权是2,第三个1的位权是1。

        在日常生活中,我们经常要和数字打交道,我们常见的数字都是十进制,例如:5,但在计算机语言中,二进制数字则是最常见的。

        在十进制中数字都是满十进一,列如当数字九再加上1时就不在个位上加减,而是进一在十位上加一;二进制则是满2进一,如数字2在二进制中也写做2,但当加一时就要进一位,写作10。

诸如此类还有8进制,16进制,原理都是一样的。

2.1 2进制转10进制

2.1.1 二进制转十进制数字 

2.2 二进制转8进制和16进制 

2.2.1 二进制转8进制

        8进制的数字都是从0~7的,写成二进制,相当于二进制三位,所以二进制转8进制时,从右到左三位转化为8进制1位,位数不够则直接换算。

        如:二进制的01101011,换成8进制:0153。0开头的数字,会被当成8进制。

2.2.2 二进制转换16进制 

        16进制的每一位都是0~7,a~f的数字,各自写成2进制,最多相当于4个二进制位。从二进制序列中右边到左边每4位组成一个16进制位,剩余不够4位直接进行换算。

        如:二进制位的01101011,换成16进制:0x6b。16进制表示的时候加上0x。

3. 原码,反码,补码

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

        有符号整数的三种表示方法均有符号位和数值位两部分,2进制序列中,最高位的1位是被当做符号位,剩余的都是数值位。

        符号位都是用0表示“正”,1表示“负”。

        正整数的原码,反码,补码都相同。

        负整数的三种表示方法各不相同。

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

        反码:将原码的符号位不变,其他位依次按位取反就可以得到反码。

        补码:反码+1就得到补码。

        补码得到原码也是可以使用:取反,+1的操作。

        对于整形来说:数据存放内存中其实存放的是补码。

原因:

        在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理(CPU只有加法器)此外,补码和原码也可以相互转换,其运算过程是相同的,不需要额外的硬件电脑。

4.  移位操作符

<< 左移操作符

>> 右移操作符

:移位操作符的操作数只能是整数。

4.1 左移操作符

移位原则:左边抛弃,右边补零

1.  #include<stdio.h>
2.  int main()
3.  {
4.  	int num = 10;
5.  	int n = num << 1;
6.  	printf("n=%d\n", n);
7.  	printf("num=%d\n", num);
8.  	return 0;
9.  }

4.2  右移操作符

移位原则:右移原则运算分两种。

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

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

1.  #include<stdio.h>
2.  int main()
3.  {
4.  	int num = 10;
5.  	int n = num >> 1;
6.  	printf("n = %d\n",n);
7.  	printf("num=%d\n", num);
8.  	return 0;
9.  }

注:对于移位运算符,不移动负数位,这个是标准未定义的。

例:

1.  int num = 10;
2.  num >> -1;//error

 5.  位操作符

位操作符有:

1. &    //按位与
2. |    //按位或
3. ^    //按位异或
4. ~    //按位取反

注:操作数必须为整数。

5.1 按位与(&)

与(&)运算符:两个操作数对应二进制位同样为1结果位才为1,否则为0;

例:

如 3&4

3的原码是:00000011

4的原码是:00000100

所以 3&4为:00000000

故 3&4=0

注:负数的运算用补码。

用途:

1. 判断奇偶

        只要根据最末位是0还是1来决定,为0就是偶数,为1就是奇数。因此可以用if ((a & 1) == 0)代替if (a % 2 == 0)来判断a是不是偶数。

2. 取一个数的指定位

        比如取数 X=1010 1110 的底4位,只需要另找一个数Y,令Y的低4位为1,其余位为0,即Y=0000 1111,然后将X与Y进行按位与运算(X&Y=0000 1110)即可得到X的指定位。

3. 清零

        如果想将一个单元清零,即使其全部二进制位为0,只要与一个各位都为零的数值相与,结果为零。

5.2 按位或(|)

或(|)运算符:两个操作数对应二进制位同样为0结果位才为0,否则为1;

如 3|4

        3的原码是:00000011

        4的原码是:00000100

        所以3|4为:00000111

        故3|4 = 7

        注:负数的运算用补码。

用途:

1.  常用来对一个数据的某些位设置为1

        比如将数 X=1010 1110 的低4位设置为1,只需要另找一个数Y,令Y的低4位为1,其余位为0,即Y=0000 1111,然后将X与Y进行按位或运算(X|Y=1010 1111)即可得到。

5.3 按位异或(^)

异或(^)运算符:两个操作数对应二进制位相同则结果位为0,不同则为1;

如 3^4

        3的原码是:00000011

        4的原码是:00000100

        所以3^4 = 00000111 = 7

         注:负数的运算用补码。

性质:

  • 1、交换律
  • 2、结合律 (a^b)^c == a^(b^c)
  • 3、对于任何数x,都有 x^x=0,x^0=x
  • 4、自反性: a^b^b=a^0=a;

用途:

1. 翻转指定位

        比如将数 X=1010 1110 的低4位进行翻转,只需要另找一个数Y,令Y的低4位为1,其余位为0,即Y=0000 1111,然后将X与Y进行异或运算(X^Y=1010 0001)即可得到。

2. 与零相异或值不变

        例如:1010 1110 ^ 0000 0000 = 1010 1110

3. 交换两个数

1.  void Swap(int &a, int &b){
2.      if (a != b){
3.          a ^= b;
4.          b ^= a;
5.          a ^= b;
6.      }
7.  }

5.4 按位取反运算符(~)

非(~,按位取反)运算符:一个二进制操作数,对应位为0,结果位为1;对应位为1,结果位为0;

用途:

1. 使一个数的最低位为零

        使a的最低位为0,可以表示为:a & ~1。~1的值为 1111 1111 1111 1110,再按"与"运算,最低位一定为0。因为" ~"运算符的优先级比算术运算符、关系运算符、逻辑运算符和其他运算符都高。

不同长度的数据进行位运算:如果两个不同长度的数据进行位运算时,系统会将二者按右端对齐,然后进行位运算。

以"与运算"为例说明如下:我们知道在C语言中long型占4个字节,int型占2个字节,如果一个long型数据与一个int型数据进行"与运算",右端对齐后,左边不足的位依下面三种情况补足,

  • 1)如果整型数据为正数,左边补16个0。
  • 2)如果整型数据为负数,左边补16个1。
  • 3)如果整形数据为无符号数,左边也补16个0。
  • 如:long a=123;int b=1;计算a& b。

    如:long a=123;int b=-1;计算a& b。

    如:long a=123;unsigned intb=1;计算a & b。

6.  逗号表达式

逗号表达式,就是逗号隔开多个表达式。

逗号表达式,从左到右依次执行,整个表达式的结果是最后一个表达式的结果。

1.  #include<stdio.h>
2.  int main()
3.  {
4.  	int a = 10;
5.  	int b = 20;
6.  	int c = (a > b, a = b + 10, a, b = a + 1);
7.  	printf("%d", c);
8.  	return 0;
9.  }

        由以上逗号表达式代码可推:a>b不成立,但并未进行赋值,往后看,a=b+10,此时a=30,然后是a,并没任何意义,接着是b=a+1,现在b为31.逗号表达式结束,整个表达式的结果是最后一个表达式的结果,故c=31.

代码一:

1.  #include<stdio.h>
2.  int main()
3.  {
4.  	int a = 10 = get_val();
5.  	count_val(a);
6.  	while (a > 0)
7.  	{
8.  		int a = get_val();
9.  		count_val(a);
10. 	}
11. 
12. 	return 0;
13. }

代码二:

1.  #include<stdio.h>
2.  int main()
3.  {
4.  	int a = 10;
5.  	while (a = get_val(),count_val(a), a > 0)
6.  	{
7.  		int a = get_val();
8.  		count_val(a);
9.  	}
10. 
11. 	return 0;
12. }

        由以上两个代码可知:代码二应用了逗号表达式,相较代码一代码更加整洁,同时也可知:while表达式括号中可以有多个表达式。

7.  下标访问[],函数调用()

7.1 下标引用操作符

操作数:一个数组名 + 一个索引值(下标)

1. int arr[10];//创建数组
2. arr[9] = 10;//使用下标引用操作符
3. [ ] 的两个操作数是arr和9.

7.2 函数调用操作符

接受一个或多个操作数:第一个操作数是函数名,剩余的操作数就是传递给函数的参数。

1.  #include<stdio.h>
2.  void test1()
3.  {
4.  	printf("hehe\n");
5.  }
6.  void test2(const char *str)
7.  {
8.  	printf("%s\n", str);
9.  }
10. int main()
11. {
12. 	test1();            //这里的()就是作为函数调用操作符
13. 	test2("hello bit.");//这里的()就是函数调用操作符
14. 	return 0;
15. }

8.  结构成员访问操作符

8.1 结构体成员的直接访问

结构体成员直接访问是通过(.)访问的。点操作符接受两个操作数。如下所示:

1.  #include<stdio.h>
2.  struct Point
3.  {
4.  	int x;
5.  	int y;
6.  }p={1,2};
7.  int main()
8.  {
9.  	printf("x:%d y:%d\n", p.x, p.y);
10. 	return 0;
11. }

使用方式:结构体变量.成员名

8.2 结果体成员的间接访问

有时我们得到的不是一个结构体变量,而是得到一个指向结构体的指针。如下所示:

1.  #include<stdio.h>
2.  struct Point
3.  {
4.  	int x;
5.  	int y;
6.  };
7.  int main()
8.  {
9.  	struct Point p = { 3,4 };
10. 	struct Point* ptr = &p;
11. 	ptr->x = 10;
12. 	ptr->y = 20;
13. 	printf("x=%d y=%d\n", ptr->x, ptr->y);
14. 	return 0;
15. }

使用方式:结构体指针->成员名

9.  操作符的属性:优先级,结合性

C语言的操作符有两个重要的属性:优先级,结合性,这两个属性决定了表达式求值的计算顺序。

优先级

优先级指的是,如果一个表达式包含多个运算符,哪个运算符应该优先执行。各种运算符的优先级是不一样的。

结合性

如果两个运算符优先级相同,优先级没办法确定先算哪个了,这时候就看结合性了,则根据运算符是左结合还是右结合,决定执行顺序。大部分运算符是左结合,少数运算符是右结合。

部分操作符由高到低排序:

  1. 圆括号()
  2. 自增运算符(++),自减运算符(- -)
  3. 单目操作符(+和-)
  4. 乘法(*),除法(/)
  5. 加法(+),减法(-)
  6. 关系运算符(<,>等)
  7. 赋值运算符(=)

由于圆括号的优先级最高,可以使用它改变其他运算符的优先级。

C 运算符优先级 - cppreference.com

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值