C语言学习笔记-运算符(二)

C
4.9k 词

一. 算术运算符

运算符 术语 示例 结果
+ 正号 +3 3
- 负号 -3 -3
+ 10 + 5 15
- 10 - 5 5
* 10 * 5 50
/ 10 / 5 2
% 取余(取模 Modulo) 10 % 3 1

1.1 注意事项

  1. 先 * / %,后 + -。
  2. 除法
    • 两整数相除,结果整数(舍小数部分)
    • 两浮点数相除,结果 double 浮点数
    • 整数和实数相除,自动类型转换为实型
    • 不允许 除 0(与数学一样)
  3. 取模(取余)
    • 运算数必须是整型
    • 对负数取余,结果为余数的绝对值
    • 不允许 除 0(与数学一样)

二. 比较运算符

运算符 作用 示例 结果
< 判断 小于 4 < 3 不成立(假):0
<= 判断 小于等于 4 <= 3 不成立(假):0
> 判断 大于 4 > 3 成立(真):1
>= 判断 大于等于 4 >= 4 成立(真):1
== 判断 相等 4 == 3 不成立(假):0
!= 判断 不相等 4 != 3 成立(真):1

注意:判断 “相等”,使用 “==”, 不能使用 “=”(赋值符)

  1. 整体,比算术运算符 低。
  2. 整体,比赋值运算符 高。
  3. > >= < <= 高于 == !=

三.赋值运算符

运算符 术语 示例 结果
+= 加等于 int a=1; a+=2;(等同于a = a+2) a值为 3;
-= 减等于 int a=5; a-=3;(等同于a = a-3) a值为 2;
*= 乘等于 int a=2; a*=2;(等同于a = a*2) a值为 4;
/= 除等于 int a=4; a/=2;(等同于a = a/2) a值为 2;
%= 模等于 int a=3; a%=2;(等同于a = a%2) a值为 1;

注意:赋值运算符,会修改变量的原始值。 赋值符左侧,必须可修改(变量)。

四. 自增减运算符

目标:实现数据的增 1、减1运算

自增自减运算也叫 增 1 减 1 运算,都是单目运算。

作用:

  • 自增 ++, 放在变量前面或后面,对变量自身值+1。
  • 自减 –, 放在变量前面或后面,对变量自身值-1。
  • 方便实现变量的 +1 或 -1 运算。
运算符 术语 示例 结果
++ 自增 int a=1; a++ 或 ++a;(等同于a = a+1) a 值为 2;
自减 int b=5; b– 或 –b;(等同于b = b-1) b 值为 4;

4.1 自增自减语法

++ 对变量值 +1。 – 对变量值 -1。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 目标: 掌握 ++ 自增1, -- 自减1 特性
int main(void)
{
int a = 10;

//a++; // a = a + 1;
++a; // a = a + 1; 与 a++ 效果相同

printf("a = %d\n", a);
//a--; // a = a -1;
--a; // a = a -1; 与 a-- 效果相同

printf("a = %d\n", a);

return 0;
}

4.2 前缀后缀区别

注意:++ 和 – 如果 ==不是单独使用==(如:用在表达式中),前缀和后缀 ==差异巨大==

  • 放在变量前,先 +1、-1 再取值使用。

    1
    2
    int a = 10;
    int res = ++a; // 先 +1,再取 a 值给 res。 (先加再用)
  • 放在变量后,先 取值用,再 +1、-1

    1
    2
    int b = 10;
    int res2 = b--; // 先取 b 值给 res2, 而后 b 再 -1 (先用再减)

4.3 注意事项

  1. 不能用于常量
  2. 不能用于表达式
  3. 优先级:整体高于算数运算符(必然高于比较、赋值);后缀高于前缀
  4. 不要在一个表达式中,对同一变量 多次 ++、– 运算。可读性差,且不用编译系统结果不同。

五. 逻辑运算符

作用:

  • 用程序解决 类似 或者、并且 这种 含有逻辑关系的 情况。

  • 将多个条件放在一起运算,最终返回 真(1)或 假(0)

运算符 术语 示例 结果 速记
&& 2>1 && 3>2 &&两边同为真,结果为真,否则为假。 同真为真
|| 2>1||3 > 5 ||两边有一个为真,结果为真,二者同为假,结果为假。 有真为真
! ! (2>1) 取反!表达式为假,加 ! 为真;表达式为真,加 ! 为假。 真非为假

六.短路运算

​ 逻辑运算符的特性,导致实际应用中一部分表达式不执行,也能得出整个表达式结果。这一特点经常作为考点出现在计算机二级、期末考试题中。

在程序中:

  • 判断 表达式 a && (b+c) 的结果:
    • 当 a 为假时,不必计算 b+c,可直接得出表达式为假的结论。
  • 判断 表达式 a || (b+c) 的结果:
    • 当 a 为真时,则不必计算 b+c,就能判断出表达式的值为 真。

**概念:逻辑表达式 运算过程中,只运算左边表达式,就能直接得出整个逻辑表达式的结果。—— 短路运算 **

6.1 短路运算作用

​ 在代码中利用短路运算,可 避免不必要运算,提高程序执行效率。 比如有如下代码:

1
2
3
int a = 5, b = 28;
int c = (a > 3) || ((b / 7)*4 % 2 != 0)
printf("c = %d\n", c);

​ 现要计算 c 值。= 右侧表达式含有逻辑或 || 运算符,运算特性 有真为真。|| 左边表达式很容易判断为 真,可确定整个表达式结果为 真。 右侧 b 相关的 复杂表达式 不需要计算 。

6.2 短路运算特性

左表达式能直接得逻辑表达式结果,右表达式不执行。

案例 1:以下代码执行后,a、b、c 的值依次是多少?

1
2
3
4
5
6
7
8
9
// 目标: 掌握运算特性
int main(void)
{
int a = 1, b = 2, c = 3;
(a = b + c) || (++b) ;
printf("a=%d, b=%d, c=%d\n", a, b, c);

return 0;
}

​ 简单分析代码。 很可能得出结论: a = 5,b = 3,c = 3

​ 但,实际上这里的 b 并没有完成自增运算,值还是 2。 为什么 有前缀 ++ 自增,b 值还是 2 呢? 因为 短路运算!++b 并未执行。

​ 逻辑 || 运算符,运算特性有真为真。 左侧 a = b+c 赋值表达式很容易得出结果为真。 因此 整个 表达式得出结论为真,右侧 ++b 并不需要执行。 因此,即使是 前缀自增,b 没有执行机会,值依然为 2。

​ 正确输出结果:a = 5,b = 2,c = 3

案例 2:分析代码,推测 a, x, y 的值分别是什么?

1
2
3
4
5
6
7
8
9
// 目标: 掌握运算特性
int main(void)
{
int x = 1, y = 5, a;
a = --x && ++y;
printf("a=%d, x=%d, y=%d\n", a, x, y);

return 0;
}

​ 同样是逻辑运算表达式,逻辑与&& 运算符,运算特性 同真为真。 x 初值为 1,前缀 –x 执行 结果为 0,假。依然会触发短路运算特性。右侧 ++y 不执行。

​ 因此,输出结果为:a=0, x=0, y=5

案例 3: 依然上述案例 2代码,将 –x 修改为 x–,输出结果为何?

1
2
3
4
5
6
7
8
9
// 目标: 掌握运算特性
int main(void)
{
int x = 1, y = 5, a;
a = x-- && ++y;
printf("a=%d, x=%d, y=%d\n", a, x, y);

return 0;
}

​ 修改后,x– 由于是 后缀,因此 先取值 1 为真(而后再-1),所以没有触发 短路运算,继续运算 右侧 ++y,将 y 值自增为 6。 1 && 6 结果为真, a 值为 1。

​ 因此,输出结果为:a=1, x=0, y=6

小知识:合理利用短路运算特性,提高程序执行效率

  • 编写含**==&&==**表达式时,&& 同真为真,左表达式值为假时,右表达式不计算, 建议将 **==易假 值放左边==**。
  • 编写含**==||==**表达式时,|| 有真为真,左表达式值为真时,右表达式不计算。 建议将 **==易真 值放左边==**。

七. 条件运算符

语法:表达式1 ?表达式 2:表达式 3

  • 表达式 1 一定起 判别 作用。表达式 2 和 表达式 3 只能有一个执行。
  • 三目运算的结果,必须被使用。

运算规则:

  • 判断 表达式 1 的结果:

    • 为真,整个三目运算的结果为 表达式 2

    • 为假,整个三目运算的结果为 表达式 3

能解决什么问题呢?比如,查询成绩系统中,根据成绩判定是否及格?可以用 三目运算来进行判断。

案例 1:接收学生成绩,判断是否 及格,给出 Y/N 结果。**

1
2
3
4
5
6
7
8
9
10
11
12
13
// 目标: 掌握 三目运算语法特性
int main(void)
{
double score;

printf("请输入成绩:");
scanf("%lf", &score);

char res = score >= 60 ? 'Y' : 'N'; // 三目运算结果 赋值给 res 变量

printf("是否及格? %c\n", res);
return 0;
}

案例 2:找出两个数中的较小值

1
2
3
4
5
6
7
8
9
// 目标: 掌握 三目运算语法特性
int main(void)
{
int a = 10;
int b = 20;

printf("较小值为:%d\n", a < b ? a : b); // 三目运算结果在 printf 中使用
return 0;
}

7.1 特性和嵌套应用

​ 嵌套条件运算符的写法,在实际编程中较少见,因为代码可读性低。 但,计算机考试中,经常出做考点。

​ 辨别技巧是,当 表达式中 有 2 个以上问号、冒号,一定是发生了 三目运算嵌套。

​ 处理方法是,先将位于右边的 “?” 与它后面最近一个 “:” 配对。因为,条件运算符的结合性,自右向左。

​ 优先级,高于赋值运算符,低于算数、逻辑、比较运算符。

案例 1:

1
int res = w < x ? x + w : x < y ? x : y   	//  w < x ? x + w :(x < y ? x : y)

​ 将 右侧的 ?与后面的 :配对,x < y ? x : y 看做一组 三目运算表达式,作为另外一组 三目运算的 表达式 3。

案例 2:

1
int res = a > b ? c > d ? e : f : g		// a > b ? (c > d ? e : f ): g

​ 将 右侧的 ?与后面的 :配对,c > d ? e : f 看做一组 三目运算表达式,作为另外一组 三目运算的 表达式 2。

​ 这种嵌套写法,看其他人写的程序时,能看懂即可。我们不要这样写。

八.逗号运算符

C语言中,逗号也是一种运算符。 用逗号将多个表达式连接起来,组成逗号表达式。一般形式为:

表达式 1,表达式 2,表达式 3,….,表达式 n

如:a+3, b+4, c+5 是一个 逗号表达式。

求解过程是 自左向右 依次求解。 整个逗号表达式的值,为最后一个表达式 n 的值。

逗号运算符的优先级,是所有运算符中最低的。

附录:运算符优先级

运算符 名称
[ ] 数组下标
() 圆括号
- 负号
++、– 自增、自减
windows:先++优于后++
mac、Linux从左到右依次计算
& 取地址运算符
逻辑非
(类型) 强制类型转换
sizeof 长度运算符
*
/
% 取余
+
-
> 大于
>= 大于等于
< 小于
<= 小于等于
== 等于
!= 不等于
&& 逻辑与
|| 逻辑或
? : 条件运算符
= 赋值运算符
/= 除后赋值
*= 乘后赋值
%= 取余后赋值
+= 加后赋值
-= 减后赋值
, 逗号运算符

笔记来源:黑马程序员

留言