C语言学习笔记:运算符

运算符

各类数值型数据间的混合运算

  • 整型、实型、字符型数据间可以进行混合运算,如:

 10 - 'a' * 1.5      // 10-97*1.5

运算时,参加运算的两个数据如果类型不同,则首先将其类型转换成一致在运算,转换规则是:

将优先级低的类型转换到优先级高的类型,被称作自动类型转换。自动类型转换的形式为:

 大类型类型 变量名 = 小类型变量;


注意:

在混合运算过程中,系统所进行的类型转换并不改变原数据的类型,只是在运算过程中将其值变成同类型后再运算。

 int a = 10;
 double c = a + 22.5;// a只是在运算过程中临时将其值变成double,但是a本身并没有改变类型
  • C语言提供了强制类型转换运算,可得到一个所需类型的数据,强制类型转换的形式为:

 (类名名)(表达式)
 -------------------------------
 小类型类型 变量名 = (小类型类型)大类型变量;
  • (double)a 将a的值转换成double类型

  • (int)(x+y) 将x+y的结果转换为int类型

  • (int)x+y 将x的值转换成Int类型后与y相加

  • (float)(5%3) 将5%3的值转换成float类型

特别需要说明的是:在强制类型转换的过程中,并不改变原变量的类型,只是在运算过程中将其值转换类型后再运算。

案例:

  • 要求:强制类型转换

 #include <stdio.h>
 ​
 void main()
 {
     float x;
     int i;
     x = 3.6F;
     i = (int)x;
     printf("x=%f,i=%d\n",x,i);// x=3.6,i=3  实数转换整数,会丢失小数部分
 }

说明:x仍然为float类型,可见强制类型转换并不改变变量的类型。

C语言运算符和C算数表达式

C运算符

序号名称符号序号名称符号
1算数运算符+、-、*、/、%、++、--8指针运算符*、&
2关系运算符>、<、>=、<=、==、!=9字节数运算符sizeof
3逻辑运算符!、&&、||10下标运算符[]
4位运算符<<、>>、~、|、^、&11强制类型转换运算符(类型)
5赋值运算符=、+=、-=、*=、/=、%=12分量运算符.、->
6条件运算符?:13其他函数调用运算符()
7逗号运算符,

C表达式

所谓表达式就是将操作对象用运算符连接起来的符合C语法规则的式子。(运算数+运算符=表达式)

序号名称举例说明
1算数表达式2+6.7*3.5+sin(0.5)计算结果是数值类型
2关系表达式x > 0,y <= z + 6计算结果是布尔类型,或0和非0
3逻辑表达式x > 0 && y > 0计算结果是布尔类型,或0和非0
4赋值表达式a = 5.6,sum+=i规则:右往左
5逗号表达式x = 3,y += 4,z -= 8分割,并列,结果是最后一个表达式的值

C语言规定了运算符的优先级和结核性。在表达式求值时,按运算符的优先级别的高低次序进行。如果我们运算对象两侧的运算符优先级别相同,如a+b+c,则按照规定的”结合方向“处理。

C语言运算符的优先级

算数运算符

基本运算符

+、-:正负值运算符,单目运算符。

+、-、*、/、%加减乘除取余运算符,双目运算符。注意:除法运算时,除数不能为0。

这些算术运算符的运算顺序与数学上的运算顺序相同。

表达式和运算符的优先级与结合性

算数表达式:是指算术运算和括号将运算对象连接起来,符合C语言语法规则的式子。例如:

 a * b / c - 1.5 + `a`
  • 表达式中各种运算符的运算顺序,必要时应添加括号,例如:

 (a+b)/(c+d) != a+b/c+d
  • 注意表达式中各运算对象的数据类型,特别是整型的相除,C语言规定,两个整型相除,其结果仍然为整型。例如:

 7/6的值为1
 4/7的值为0
 (1/2)+(1/2)的值为0

优先级与结合性:在表达式求解的时候,先按运算符的优先级别高低次序执行。若一个运算对象两侧的运算符的优先级相同,则按规定的结合方向处理。

各种运算符的结合方向:

① 算术运算符的结合方向:“自左向右”,即运算对象先与左边的运算符结合,例如:

 a-b+c    // 先执行a-b,然后再执行+c运算

② 有些运算符的结合方向:“自右向左”,即运算对象先与右边的运算符结合,例如:

 i++

③ 若一个运算符两侧的数据类型不同,会自动转换成同类型后进行计算。

自增++、自减--运算符

作用:使变量的值增1或者减1

结合方向:“自右向左”

++i,-11

表示在使用运算对象之前,先让自身增1或减1,然后再使用它,也就是使用增1或者减1后的值。先计算,后赋值

例如:语句x = ++n;相当于以下两个语句的运算结果:n=n+0;x=n

 int n = 1;
 int x = ++n;

i++i--

表示在使用运算对象之后,才让自身增1或减1,也就是使用它的值,再让增1或者减1。先赋值,后计算

例如:语句x = n++;相当于以下两个语句的运算结果:x = n; n = n + 1

 int n =1;
 int x = n++

总结:不管是++i还是i++,自身i都增1;同理不管是i--,还是i--,它们的不同之处在于赋值的先后顺序。

注意:

① 增1与减1运算符只适用于整型变量或字符型变量,而不能用于其他类型的变量

② 增1与减1运算符不能用于常量或表达式,例如:--5(i+j)++等都是非法的

课堂练习

要求:推到以下表达式i和n的值

 int i = 1;
 int n = i++ + (++i) - (--i) + i--;

赋值运算符

“=”称之为赋值运算符,其作用是将一个数据赋值一个变量。如:a = 5

执行赋值运算的结果,是将右边的数据存入左边变量对应的内存单元中,赋值运算的顺序:由右向左

赋值规则

如果赋值运算符两侧的类型不一致,则在赋值时要进行类型转换,转换规则为:

  • 实型→整型变量:舍弃小数部分

  • 整型→实型变量:数值不变,以浮点形式存储

  • 字符型→整型变量:放在整型低8位。保持原值不变原则。比如: int a = 'A'

赋值表达式

主要实现赋值运算的表达式

语法:

 变量 = 表达式

案例:

 a = 5;
 y = 2 * x + 3;
 a = a + 7

作用:将右边表达式的值赋值给左边的变量。赋值表达式的值取自左边变量的值。

复合赋值运算符

+= -= *= /= %= ....

左右两侧操作完毕后,赋值给左侧的变量,例如:

 a += 3;         // 等价于a = a + 3
 int c = 2;      // 等价于a = a / c
 a /= c; 

注意:

① 在运算时,不能将单括号(=)双括号(==)

② 赋值运算符的优先级属于最低(除了逗号运算符以外)一般最后运算

关系运算符

< > <= >= == !=

  • 所有的关系运算符都是二元运算符,左侧和右侧可以是变量,也可以是常量,还可以是表达式;举例:a>b、5>6、a+b>c

  • 关系运算符运算的结果是布尔类型,要么为真(非0,true),要么为假(0,false)

说明:

  1. 标准C中没有布尔类型的,非0代表真,0代表假

while(0) 循环一次都不执行

while(1) 死循环,无限循环

  1. 真在输出的结果为1,假在输出的结果位0

printf("%d\n",3<2); // 结果为0

printf("%d\n",3>2); // 结果为1

说明:用作条件判断的时候,非0代表真,但是系统输出真的结果是1

注意:

① 算数运算符的优先级高于关系运算符

② 关系运算符是二元运算符,不要连用 例如:5>a>1(恒等于0) 3<b<10(恒等于1)可以编译和运行,不报错,没有意义

前面案例正确的写法:a<5 && a>1b>3 && b<10

③ 不能将==写成=,==:关系运算符,=:是赋值运算符

④ 一般浮点型进行比较,建议将两个数相减,结果和0进行比较,如果等于0,表示这两个浮点数相等

案例1:

float a = 22.2

float b = 22.2

a == b 结果为真;a!=b结果为假

案例2:

float x = 2.0

float y = 11.1 // 近似存储:11.099995

float z = x * y // 实际是:22.19999,我们以为:22.2

逻辑运算符

运算的结果要么是真(1),要么是假(0)

!:非(逻辑非)单目运算符,并且只能放在操作数的左侧;非真即为假,非假即为真。(取反)

对一个数或者表达式取非奇数次,结果与原值相反,!(a % 2 !== 0)取偶数次

对一个数或者表达式取非偶数次,结果与原值相反,!(a % 2 == 0)取奇数次

&&:与(逻辑与)双目运算符,当左右两侧的数据都为真时,最终的结果才为真(有假则为假)

当逻辑与运算时,左侧为假,右侧结果不会影响最终的结果,右侧就不会执行,结果直接为假,这种现象称为短路效果(短路&)。

||:或(逻辑或)双目运算符,当左右两侧的数据都为假时,最终结果才为假(有真则真)

当逻辑与运算时,左侧为真,右侧的结果不会影响最终的结果,右侧压根不会执行,最终结果为真,这种现象称为短路效果。

小结:短路&与短路|被称之为惰性运算。

逗号运算符

作用:将若干个表达式“串联起来”,如:3+5,6+8

别称:顺序求值运算符

逗号表达式

语法:

 表达式1,表达式n,...,表达式n

求解过程:按从左到右的顺序分别计算表达式值,其中最后一个表达式n的值就是整个逗号表达式的值。

位运算

说明:按位(bit)来进行运算操作的运算符

语法:~ & | ^ << >>

~:按位取反

说明:单目运算符,数据的每一个bit位取反,也就是二进制数位上的0变1,1变0

举例:

 unsigned char ret = ~0x05; // 0000 0101 --> 1111 1010
 printf("%d\n",~5); // -6   // %d:有符号十进制int,%u:无符号十进制int

&:按位与

运算规则:对与左右操作数,只有相应二进制位数据都为1时,结果数据对应数据为1,简单来说:

你为1,我为1,结果就是1

举例:

 5 & 6  // 0101 & 0110 = 0100

作用:

① 获取某二进制位的数据

② 将指定二进制位数据清零

③ 保留指定位

|:按位或

运算规则:对于左右操作数据,只要相应二进制位数据有一个为1,结果数据对应位数据为1,简单来说:

你是1 或 我是1 结果就是1

举例:

 5 | 6  // 0101 | 0110 = 0111

作用:

① 置位某二进制位数据

^:按位亦或

运算规则:对于左右操作数据,只要相应二进制位数据相同,结果数据对应位数据为0,不同为1,简单来说:

你我相同,结果为0;你我不同,结果为1

 5 | 6  // 0101 | 0110 = 0011

作用:

① 翻转

② 值交换

<<:左移,按位往左偏移

运算规则:原操作数所有的二进制位数向左移动指定位

无符号左移:

  • 语法:操作数 << 移动位数

 unsigned int a = 3 << 3;  // 计算规则:3*2^3
 unsigned int b = 5 << 4;  // 计算规则:5*2^4
 printf("%d\n",a);  // 24

有符号左移:

  • 语法:操作数 << 移动位数

 int a = 3 << 3;  // -3*2^3
 printf("%d\n",a);  // -24
  • 注意:

    • 如果移出的高位都是0,我们可以这样理解:a << n,可以看作是: a*2^n

    • 如果移出的高位是1,我们是不能使用上面的计算公式的

>>:右移,按位往右偏移

运算规则:原操作数所有的二进制位数据向右移动指定位,移出的数据舍弃。

如果操作数是无符号数:左边用0补齐

如果操作数是有符号数:左边用什么去补全,取决于计算机系统:

  • 逻辑右移:用0补全

  • 算数右移:用1补全

大部分情况下,系统是遵循“算数右移”的

无符号右移:

  • 语法:操作数 >> 移动位数

 unsigned char a = 3 >> 3;
 printf("%d\n",a); // 0

有符号右移:

  • 语法:操作数 >> 移动位数

 unsigned char a = -3 >> 3;
 printf("%d\n",a); // -1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值