C语言运算符-基本知识概念与编程技巧(4)

本章主要讲述C语言的运算符

在数据处理中,离不开运算符的帮助。

运算符是一种告诉编译器执行特定的数学或逻辑操作的符号。C 语言内置了丰富的运算符,并提供了以下类型的运算符:

①算数运算符

算数运算符均为二元运算符,即需要两个对象才能完成操作。包括+-*/等。

求模运算符%,用于整数运算用于得到两个整数相除的余数。余数可以是正数也可以是负数,由%号左边的数决定,在C99标准中规定,如果第一个运算对象是负数,那么求模的结果为负数,如果第一个运算对象为正数,那么求模的结果也是正数。

②自增自减运算符

虽然自增自减运算符也是算术运算符,但由于其特别需要注意模式不同的差异,所以这里单独来讲。

以自增运算符为例。前缀自增,将++写在变量前面,而后缀的++写在后面。虽然++i和i++都相当于i=i+1,使用其主要是为了代码简洁性,但两者还是有区别的。

前缀自增,可概括为先自增后引用,引用代表着使用变量的值,即把变量的值存入操作数栈(临时空间),而后缀模式则为先引用后自增。这里令a的值为2,你输出a++或者++a,会发现输出值均为3,所以若语句中仅有自增运算符,其效果没有区别,因为这里并没有将变量的值存入操作数栈。但你将其赋值给其它变量,就会发现差异。比如b=++a,输出b会发现b为3,按先自增后引用的逻辑,这里a的值先自增为3,然后再赋值给b,所以b的值也是3。而当b=a++时,这时输出b的值即为2,为什么呢?当程序中需要用到变量的值,计算机是从操作数栈中取出值进行运算,变量参与赋值运算时其数值就会被存入操作数栈,而后缀模式的先引用后自增规则,让其先取出a的值2存入操作数栈,然后a的值才自增为3,接下来才进行赋值操作,使用刚刚存入操作数栈的值对变量b进行赋值,所以b为2。之前前缀模式先完成了自增操作然后才把值存入操作数栈,这便是两种模式的区别。

//以下示例均在Intellij IDEA中运行通过
int a = 2;
int b = ++a + ++a;
/*
按照运算符优先级
计算机首先自增a
然后将自增所得的值3存入操作数栈(这里称为1号数栈)
由于表达式中还有个自增
所以继续对a进行自增运算
将自增所得的值4存入操作数栈(这里称为2号数栈)
接着按照优先级顺序实现加法运算
计算机将1号数栈和2号数栈的值取出并进行加法运算
所以这里a的值为4,b的值为7
*/
int c = ++a + a++ + ++a;
/*
若这样,即a先进行自增
然后将结果3存入3号数栈
后面的自增由于是后缀模式
遵循先引用后自增的规则
所以先取出3号数栈的3
然后存入4号数栈
这时前两项的和实际为6
但这时a的值已经通过两次自增成为了4
所以第三次自增使a的值成为5并存入了数栈
所以总结果为11
*/

如果将自增的结果赋值给自身,以上述变量a还是为2为例,若a=++a,这时将前缀自增结果赋值给自身,所以遵循先自增后引用的规则,将自增后a的值3存入操作数栈,然后赋值,所以表达式还是为3。而若写成a=a++,遵循先引用后自增的原则,先把a的值2存入操作数栈,接着再进行自增运算,a的值变成了3,赋值时利用操作数栈的值进行赋值,所以表达式的值还是2。虽然自增优先级高于赋值,但如果a+=++a + ++a,这时应先把+=左边的数值存入操作数栈,然后才计算+=右边的值7存入另一个操作数栈,最后才将两个操作数栈的值相加存入变量a中得到9。

递减运算符与递增运算符同理。

③关系运算符

在循环中,经常会依赖关系运算符做比较,用于检查关系表达式为真还是假。如下:

运算符含义
<小于
<=小于或等于
==等于
>=大于或等于
>大于
!=不等于

④其它赋值运算符

例如+=、-=、*=、/=、%=,这类运算符用于更新变量,其用法是把左边操作数对右边操作数进行第一个运算符的过程的结果赋值给左边操作数。

time += 2;
time = time + 2;
//此两个表达式等价,其它赋值运算符同理。

⑤逻辑运算符

多个关系表达式的组合,经常用于控制语句的判断作为测试条件。 

逻辑运算符描述
&&与。两侧条件为真表达式才为真
||或。两侧条件任意一个为真则表达式为真
非。将条件为真的逆转为假,反之同理,写于表达式前面

⑥条件运算符

条运算符件?:,条件运算符用于条件表达式,作为if else语句的一种便捷表达方式,用于让代码更简洁。其两个符号分隔三个运算对象,属于三元表达式,?:条件运算符也是C语言中唯一的三元运算符。如下

x = (y < 0) ? -y : y;

//两段代码等价

if (y < 0)
    x = -y;
else
    x = y;

⑦位运算符

位运算符作用于位,并逐位执行操作,全部按照二进制位进行运算。

运算符描述
&按位与。有0则为0。
|按位或。有1则为1。
^异或。仅一个1为1。
~取反。可理解为~x=-1-x。
<<二进制左移。左边的二进制位丢弃,右边补0。
>>二进制右移。正数左补0,负数左补1,右边丢弃。
//运算规则
0&0=0;   
0&1=0;    
1&0=0;     
1&1=1;

0|0=0;   
0|1=1;   
1|0=1;    
1|1=1;

0^0=0;   
0^1=1;   
1^0=1;  
1^1=0;

~1=-2;   
~0=-1;

如果两个不同长度的数据进行位运算时,系统会将二者按右端对齐,然后进行位运算。例如,由于 C 语言中 long 型占 4 个字节,int 型占 2 个字节,如果一个 long 型数据与一个 int 型数据进行与运算,右端对齐后,左边不足的位自动补足,正数左边补16个0,负数左边补16个1。其它类型1同理。

 
运算符优先级:

正如普通的算数逻辑,乘除法优先级高于加减法,所以先执行乘除法。如果两个运算符优先级相同,则根据它们出现的顺序从左到右来执行,当出现括号时,先计算括号内的表达式。关系运算符优先级低于算数运算符,高于赋值运算符。自增自减运算符的优先级高于普通算数运算符,仅低于圆括号。==和!=一般优先级会低于< <= > >=。逻辑运算符&&的优先级高于||的优先级,但都低于关系运算符,高于赋值运算符,而!运算符只低于圆括号的优先级。当不记得优先级时,建议均加上圆括号,这样也会使表达的含义更清晰。

类型转换:

通常,在语句和表达式中应使用类型相同的变量和常量,如果混用类型,则会采取自动类型转换,一般两个不同类型的数据进行运算,编译器会将其自动升级为高等级的数据类型,一般不会降级,因为较低类型可能放不下整个数字。浮点数降级为整数会直接截断,所以,一般情况应该避免自动类型转换,特别是类型降级。如果需要进行精确的类型转换,需要使用强制类型转换,即在某个量前面放置用圆括号括起来的希望转换的目标类型名

注意:

1.在运算符+-写在一个值前时,属于一元运算符,只用于一个运算对象时,表示正负。

2.除法运算符若用作整数除法时,丢弃整个小数部分,并不会四舍五入,这一过程被称为截断。一般情况下,尽量避免使用混合类型。

3,使用关系表达式时,若使用浮点数,尽量不带有等号,因为浮点数的舍入误差会导致其应相等的两数实际上并不相等。

4.C99标准中新增的_Bool类型可以用于循环,来实现用代数表示逻辑和解决逻辑问题,用布尔变量来存储真或假,其中1表示真(true),0表示假(false),在_Bool类型中,其它非零数值也会被设置成1。

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值