操作符详解

操作符共12中,分别是:

算术操作符:+ ,-,*,/,

移位操作符:>>,<<;

位操作符:&,|,^;

赋值操作符:=,+=,-= , /= , %= , >>= , <<= , &= , |= , ^= ;

单目操作符:!,- , + , & , sizeof , ~ , --  , ++ , * , (类型);

关系操作符:> , >= , < , <= , != , == ;

逻辑操作符: &&, || ,

条件操作符:  表达式1?表达式2:表达式3 ;

逗号操作符: exp1,exp2 ,exp3 ,exp4 ,exp5 ,…………

下标引用操作符: [ ];

函数调用操作符: ( );

结构体操作符: .  , ->;

以上就是全部的操作符了,接下来我们细细讲解每一种操作符的作用以及一些特殊的列子。

1:算术操作符 

 +,-,*,/,%

+,-,*,/,都如字面上表示,分别是加减乘除的作用,优先率和数学上相同,但是除号有一点不同,它的计算分为整数相除和浮点数相除;

整数相除就是所得结果是整数,若是小数点后面有数字,就直接归零,比如3/2 = 1;

而浮点数相除所得结果就是浮点数,需要除号两边至少有一边是浮点数,比如3/2 = 1.5;

然后有一个特殊的算术操作符,%操作符,这个操作符被叫做取模操作符,作用是计算%左边的数除以%右边的数的余数,如5%2 = 3;

2:移位操作符

>>,<<

 在讲这个操作符之前,我们需要了解数据在计算机中是如何存储的,首先,任何一个数据都能用二进制表示,这里我们用整数型int的数据来说明。

整数型int用sizeof计算可以直到int类型有4个字节,而一个字节又有八个比特位,这里每一个比特位就用来存储二进制中的0和1,因此一个整数型的数据有32个0/1组成的二进制序列,而整数又分为正数与负数,在计算机中,有符号整数的二进制序列中,最高位是符号位,0表示正数,1表示负数;

而计算机对于数据的存储并不是简单的将数据化为二进制存储,在这其中又细分为原码,反码,补码,我们先来结束一下三种码是怎么一回事吧;

1:原码:

原码实际上就是将一个数据转化为二进制序列时产生的;

2:反码

反码就如字面意义,是原码按除符号位以外的数按位取反,1变为0,0变为1;

3:补码

补码实际上就是反码+1;

而正数负数的原码,反码,补码也有不同,正数的原反补三码相同,负数就按照上面所说,分别转化而来,而在计算机中,一般存储的都是数据的补码,在使用的时候再转换为原码来使用。

而移位操作符就是对这个补码进行一些操作,我们先讲讲左移操作符。

1:左移操作符

<<

左移操作符实际上就是将二进制序列的补码左移一位,舍弃最左边的那一位,然后右边空出的一位补上一个0;

但是这个实际上并不会让数据变化,需要用赋值操作符才能保存下来;

比如我们这样写代码:

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

 结果是这样:

这里我们简单计算一下:

a = 5,a的二进制序列补码是:

00000000000000000000000000000101

左移一位后变为

00000000000000000000000000001010

根据二进制转换为十进制,可得b = 10;

然后简单讲一下右移操作符:

2:右移操作符

>>

 右移操作符分为两种移位:

算术移位:右边丢弃,左边补原符号位

逻辑移位:右边丢弃,左边补0

整数一般是逻辑移位,负数是算术移位;

我们来看下右移实际操作吧;

我们看看正负两数的操作吧

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

 来简单计算一下;

5的二进制序列补码是:

00000000000000000000000000000101

右移一位后变为:

00000000000000000000000000000010

计算得2;

-5的二进制序列补码是:

111111111111111111111111111111111010

右移一位后变为

111111111111111111111111111111111101

然后变为反码得:

111111111111111111111111111111111100;

再转化为原码

1000000000000000000000000000011;

通过计算得-3;

3 位操作符

&,|,^

在上面将了移位操作符再来了解改操作符就简单多了

先讲讲三个操作符的作用吧

&:按位与,有0为0,全1为1;

|:按位或,有1为1,全0为0;

^:按位异或,相同为0,不同为1;

这三个操作符也对符号位有作用,所以若是正数和负数相&,得到的一定为正,正负相  |  ,一定为负数,正数负数 ^ 也一定是负数。

这几个操作符有很大的作用,这里有一个问题:求出一个数中有几个1(除符号位)

思路是这样,我们可以计算一下,发现,一个数若是&这个数-1的数,那么就会发现数据会少一个1;

比如我们设a = 15,

它的二进制序列

00000000000000000000000000001111;

而14的二进制序列为

00000000000000000000000000001110;

二者&得

00000000000000000000000000001110;

不断重复直到这个数为0,就能得到该数有几个1了,代码如下:

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

结果如下: 

 4:赋值操作符

=,%=,+=,-=,/=,>>=,<<=,&=,|=,^=;

赋值操作符有以上,具体作用就是将值赋给变量,并且会根据=左边的符号对数据变量进行操作并且将结果赋给变量。

5:单目操作符

!  逻辑反

- 负值

 + 正值

& 取地址

sizeof()   求操作符类型长度(字节为单位)

~  按位取反(对补码操作)、

--   前置--,后置--;

++ 前置++,后置++;

*  间接访问操作符 (解引用操作符)

(类型)  强制类型转换

这些相信大家基本都遇过,我就讲两个特殊点的吧;

首先是~操作符

它的作用是将1变为0,0变为1;

当然它也有妙用;

可以限制将变量第n位的数据取反,

代码如下:

#include<stdio.h>
int main()
{
	int a;
	scanf("%d", &a);
	int n = 0;
	scanf("%d", &n);
	a &= (~(1 << (n - 1)));
	printf("a = %d", a);
	return 0;
}

 我输入15,并且让它将第一位的1变为0,可以得到14,结果如下:

 

 然后是sizeof这个操作符:

sizeof在计算变量字节大小的时候,可以省略括号,比如

int a = 0;
sizeof a;

这里是可以计算出a的字节大小的,但不能这样

sizeof int

计算变量大小的时候,需要加上括号才能进行。

顺带一提(sizeof具有返回值,返回一个无符号整形)

 6:关系操作符

==,>=,<=,>,<,!=

这些操作符唯一一个要注意的是==,在判断的时候不要写成

还有一点是关系操作符是不能比较字符串的大小的,字符串的大小比较只能用strcmp函数来比较。

7:逻辑操作符

&&  全真则真,有假则假

||   全假为假,有真则真

在c语言中,0表示为假,非0表示为真


这两个需要注意的只有一点,

当&&操作符左边有一个为假,那么右边就不会计算了,而 || 操作符左边有一个为真,那么右边就不会计算了,证明可以看下面的代码:

#include<stdio.h>
int main()
{
	int a = 0, b = 1, c = 2;
	int d = (a++ && b++ && ++c);
	printf("a = %d,b = %d,c = %d", a, b, c);
	return 0;
}

 上面的a++是后置++,因此是先使用再++,因此在判断的时候,a依旧 = 0,然后我们可以看到后面的b和c都没有变化

而 || 也是同样的:

#include<stdio.h>
int main()
{
	int a = 0, b = 1, c = 2;
	int d = (++a || b++ || ++c);
	printf("a = %d,b = %d,c = %d", a, b, c);
	return 0;
}

 这里的a是前置++,因此在使用的时候是先++,由0变为1,因此此处第一个就是真,所以后面的值都没变。

8:条件操作符

exp1?exp2 :exp3 ;

这个很简单,若是exp1为假,就会使用exp3,exp1为真,就用exp2;

实际运用如下:

#include<stdio.h>
int main()
{
	int a = 0, b = 1, c = 2;
	a = b > c ? b : c;
	printf("a = %d", a);
	return 0;
}

 

9:逗号操作符

逗号操作符会将最后一个逗号赋给其他变量,当然前面的表达式也会运行,比如:

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

 

 这里可以看到,b最后的值变成了最后一个++a所计算出的4,而a的值也有变化。

但是若是b没有括号,那么就会将第一个逗号前的表达式的值给b,比如上面的代码去掉括号后会这样:

10:下标引用操作符

[ ]

这个就是数组使用的时候,会用来寻找数组内的元素,这里给大家看一个大家应该没看过的操作:

#include<stdio.h>
int main()
{
	int a[10] = {1,2,3,4,5,6,7,8,9,10};

	printf("a[7] = %d\n", 7[a]);
	return 0;
}

 

 这里就能说明 [ ] 是一个操作符,但是希望各位看到这个操作知道就行,最好不写,不然会导致代码可读性下降;

11:函数调用

()

函数操作符不用说,就是调用函数时用的。

12:结构体操作符

.

->

这两个操作符是用来引用结构体变量的内部成员的

不同点是 第一个操作符不能用于结构体指针,而第二个用于引用结构体指针的成员 

接下我们讲一下表达式求值

 表达式求值

 计算机在进行表达式求值的时候,会有一个隐式类型转换,会将字符类型或者short数值的二进制补码序列提升到普通整形的长度,然后再切断成字符类型或者short类型的长度再计算

整型提升的原因如下:

我们这里拿char类型来说明,char类型只有8个bit位,但是int有32个比特位,若是直接转换为整形给char类型的变量,无法存储,因此编译器会截取后8位放入变量中,使用时,再根据第8位是1还是0来补充,看是补充1还是补充0;当然这里char类型变量在计算机中也是存储的补码,需要根据第8位是1还是0来还原成原码。

这里给出两个简单的实列来简单的说明一下什么是整型提升

char c1 = 1;

char c2 = -1;

1是一个正数,它的补码是00000000 00000000 00000000 00000001;

然后由于c1是char类型的,只能存储后八位数据,因此c1中存储的是00000001,只有在使用的时候就会换原成00000000 00000000 00000000 00000001

而-1补码是111111111 111111111 111111111 111111111

c2中存储的是后八位数据也就是 111111111,在使用的时候会补1然后成111111111 111111111 111111111 111111111,再还原成原码。

表达式求值还有一种转换是算术转换,计算机会根据这个列表的进行算术转换

long double

double

float

unsigned long int

long int

unsigned int 

int

当有两个列表中的类型的数据在计算时,计算机会将层次低的类型提升至层次高的类型后计算,但是算术转换应合理,否则会出现bug。

  • 12
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值