Linux_C编(2)运算符、表达式

二、运算符、表达式

一、运算符简介

C语言的运算符可以分为以下几类:
(1)算数运算符:用于各类数值运算,包括加(+)、减(-)、乘()、除(/)、取余或者求模(%)、自增(++)、自减(–),共七种;
(2)关系运算符:用于比较运算,包括大于(>)、小于(<)、等于(==)、大于等于(>=)、小于等于(<=)、不等于(!=),共六种;
(3)逻辑运算符:用于逻辑运算,包括与(&&)、或(||)、非(!),共三种;
(4)位操作运算符:参与运算的量,按照二进制位进行运算,包括位与(&)、位或(|)、位非(~)、位异或(^)、左移(<<)、右移(>>),共六种;注意,并没有按位同或,按位同或就是异或的取反,同时需要注意按位或和按位与以及按位以为的区别,具体可以看看位运算的详解以及
异或的使用

(5)赋值运算符:用于赋值运算,分为简单赋值(=)、复合算术赋值(+=、-=、
=、=、%=)、复合位运算赋值(&=、|=、^=、>>=、<<=)三类共十一种;
(6)条件运算符:这是一个三目运算符,用于条件求值(?:);
(7)逗号运算符:用于把若干表达式组合成一个表达式(,);
(8)指针运算符:用于取内容(*)和取地址(&)两种运算;
(9)求字节数运算符:用于计算数据类型所占的字节数(sizeof);
(10)特殊运算符:有括号()、下标[]、成员(->、)等几种。

1. 运算符优先级:
在这里插入图片描述在这里插入图片描述

在这里插入图片描述
上表不容易记住,其实多用用就记得容易了,自己写代码的时候可以加入括号,但是阅读别人的代码的时候,别人不一定添加括号,不能以自己的标准去衡量别人,这是很重要的。

2、一些容易出错的优先级问题
优先级问题
(1).的优先级高于*,->操作符用于消除这个问题
例如:*p.f
误以为的结果:p所指对象的字段f (*p).f
实际结果:对p取f字段,作为指针,然后进行接触引用操作, *(p.f)

(2)[]高于*
例如:int *ap[]
误以为的结果:ap是个指向int 数组的指针 int (*ap)[]
实际的结果:ap是个元素为int 指针的数组 int *(ap[])

(3)函数()高于*
例如:int *fp()
误以为的结果:fp是个函数指针,所指函数返回int int(*fp)()
实际结果:fp是个函数,返回int * int *(fp())

(4)==和!=高于位操作
例如:(val & mask!=0)
误以为的结果:(val&mask)!=0
实际结果:val & (mask!=0)

(5)==和!=高于赋值符
例如:c = getchar()!=EOF
误以为的结果:(c=getchar())!=EOF
实际结果:c = (getchar()!=EOF)

(6)算术运算符高于移位运算符
例如:msb<<4+lsb
误以为的结果:(msb<<4)+lsb
实际结果:msb<<(4+lsb)

(7)逗号运算符的优先级在所有的里面优先级最低
例如:I = 1,2
误以为的结果:(I = 1,2)
实际结果:(I = 1),2

3、逻辑运算符
||和&&是我们经常用到的逻辑运算符,与按位与&和按位|或是两码事。
例如:

int i = 0;
int j = 0;
if(++i>0)||(++j>0)
{
	//打印出i和j的值
}

结果大家都知道,i=1;j=0
这样的现象就是所谓的“与断路”和“或断路”
即逻辑运算符||两边的条件只要有一个为真,其结果就为真,只要有一个为假,那结果就为假。
详细的可以看这篇博客C语言中的短路和断路

二、条件运算符和条件表达式

如果在条件语句中,只执行单个的赋值语句时,常可使用条件表达式来实现,不但使程序简洁,也可提高运行效率。
条件运算符为?: 它是一个三目运算符,即有三个参与运算的量,由条件运算符组成条件表达式的一般形式为
表达式1?表达式2:表达式3
其求值的规则为:如果表达式1的值为真,则以表达式2的值作为条件表达式的值,否则以表达式3的值作为整个条件表达式的值。
常用来简化程序,例如:

if (a>b)
{
	max = a;
}
else
{		
	max = b;
}

可以用条件表达式写成:

max = a>b?a:b;

执行该语句的语义是:如果a>b,就把a赋值给max,否则,把b赋值给max,即求两个数字的最大值。
使用条件运算符应该注意
(1)条件运算符的运算优先级低于关系运算符和算术运算度,但是高于赋值符。因此:

max = (a>b)?a:b

去掉括号可以写为

max = a>b?a:b

(2)条件运算符“?”和“:”是一堆运算符,不能单独分开使用,也就是不能缺少一个。
(3)条件运算符的结合方向是自右向左结合。例如:

a>b?a:c>d?c:d

应该理解为

a>b?a:(c>d?c:d)

也就是条件表达式嵌套的用法,一般先从右边的三目运算开始逐个向左边开始运算。

三、++、–操作符

++、-- 通常情况下都是令人头疼的操作符……………………………………
我开始时候也被搞的云里雾里,不知道怎么算,不过熟练了之后,也就能算对了。
例如:

int i = 3;
(++i)+(++i)+(++i);
//求表达式的值

表达式的值为多少?梁老师在书上说C语言标准并没有规定这个,有的编译器运算出来是18,因为i经过三次自增后变为6,然后3个6相加得18,而有的编译器计算出来得16(我用gcc编译器,确实得出来16),先计算前两个i的和,这时候i自加两次,2个i的和为10,然后再加上第三次自加的i得16,其实没有争议的必要,因为自己有自己的编译器,适合自己使用就行。但是无论哪个编译器都不会算出来是15!
在这里插入图片描述
上下两个结果分别是15,16
区别在于上面的分别用j,k,y来装了++i,运行结果就是4+5+6,因为这三个中间变量没有被赋其他的值。
而下面直接是++i,这三个的变量名其实是一样的,而自增的运算优先级较高,并且是右结合,从右往左开始计算,最右边++i之后,i=4,接着算中间的++i,变成5,这时候++i等于5,最右边的++i也是5,这样就变成两个++i相加,等于10,这时候i还是5,再到最左边的一个++i,i等于6,++i也是6,即6+10=16。
这时候小伙伴可能问我为什么自增的优先级高于算术优先级,那为什么编译器不直接先算3个++i,确实,你说的没错,有的编译器确实是这样,结果等于18,但是也有编译器等于16,每个编译器做的时候有自己的想法,就比如vs,他觉得scanf有问题,所以这个函数它会报错,但是老谭觉得超好用,就直接把stdio的库加在了第一行,我们究竟这个没有意义,总之等于18或者16的原因都有了,至于怎么用,就看你自己的编译器了。

++、-- 作为前缀,我们知道是自增或者自减,再做别的运算,但是作为后缀时,还需要注意什么时候自增自减。
在这里插入图片描述
i = 3;
i++ = 3; i = 4;
i++ = 4; i = 5;
i++ = 5; i = 6;
逗号运算符从左到右依次计算,然后赋值给j,所以j=5,i=6;

逗号运算符的问题

#include<stdio.h>
int main()
{
	int i = 0;
	for(i = 0,printf("Frist = %d",i);i<10,printf("Second = %d",i);i++,printf("Third = %d",i))
	{
		printf("Fourth = %d",i);
	}
}

运行的结果是什么?为什么?
变成

四、位运算

在计算机程序中,数据的位是可以操作的最小数据单位,理论上可以用“位运算”来完成所有的运算和操作,一般的位运算是用来控制硬件的,或者进行数据变换的时候使用。C语言提供了位运算的功能,这使得C语言也能像汇编一样用来编写系统程序。
位运算符C语言提供了六种运算符:按位与(&)、按位或(|)、按位异或(^)、取反(~)、左移(<<)、右移(>>)
(1)、按位与运算及应用
按位与运算符(&)是双目运算符。其功能是参与运算的两个数字对应的二进制位相与。只有对应的两个二进制均为1时,结果位才为1,否则为0。参与运算的数以补码方式出现,例如:
9&5:
0000 1001 (9的二进制补码)& 0000 0101(5的二进制补码)
0000 0001(1的二进制补码)
所以9&5=1
按位与运算通常用来对某些位清零或者保留某些位。例如:把a的高八位清零,保留低八位,可以用a&255运算,因为255的二进制补码为0000000011111111
(2)、按位或运算及应用
按位或运算符“|”是一个双目运算符,其功能是参与运算的两个数字对应的二进制位相或。只要对应的两个二进制位有一个是1时,结果位就是1,参与运算 两个数字以补码方式出现。
同样,我们用9|5来举例:
0000 1001 | 0000 0101
0000 1101 (十进制为13)
可见9|5=13
应用:常用来将源操作数某些位置一,其他位保持不变。
(3)、按位异或运算及应用
按位异或运算符“^”是一个双目运算符,其功能是参与运算的两个数字对应的二进制位相异或,当两对应的二进制相异时,结果为1。参与运算数还是以补码方式出现。
例如:
9^5:
0000 1001 ^ 0000 0101
0000 1100(12)
应用:
使特定位的值取反
不引入第三变量,交换两个变量的值。
异或的特征:
x^x = 0;
x^0 = x;
a = a^b;
b = a^b; //因为这里b = a ^ b ^ b,异或有结合律,根据特征,后面为0,a^0=a;b = a;
a = a^b;
(4)左移和右移
左移(<<)是双目运算符,其功能是把"<<“左边的运算数的各个二进制位全部左移若干位,由”<<"右边的数指定移动的位数,高位丢弃,低位补零;
右移(>>)是双目运算符,其功能和左移相反,但是注意:对于有符号位的数,在右移时,符号位也跟随移动,当为正数时,最高位补0,当为负数时,最高位补1。

(五)、C语言性能优化:使用位操作

使用位操作可以减少除法和取模的运算,在计算机程中数据的位是可以操作的小数据单位,理论上可以用“位运算”来完成所有的运算和操作。一般的位操作时用来控制硬件的,或者进行数据交换,但是,灵活的位操作可以有效地提高程序运行的效率。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值