1. 算术运算符
运算符 | 术语 | 示例 | 结果 |
---|---|---|---|
+ | 正号 | +3 | 3 |
- | 负号 | -3 | -3 |
+ | 加 | 10 + 5 | 15 |
- | 减 | 10 - 5 | 5 |
* | 乘 | 10 * 5 | 50 |
/ | 除 | 10 / 5 | 2 |
% | 取余(取模 Modulo) | 10 % 3 | 1 |
// 目标:掌握算数运算的基本语法
int main(void)
{
int m = +3;
int n = -3;
printf("m=%d, n=%d\n", m, n);
int a = 10, b = 5;
printf("a+b=%d\n", a + b);
printf("a-b=%d\n", a - b);
printf("a*b=%d\n", a * b);
printf("a/b=%d\n", a / b);
printf("10%%3=%d\n", 10 % 3); // 在printf的格式串中显示 %号, 需要使用 %%
// 3 % 10 取余结果是多少呢?
printf("3%%10=%d\n", 3 % 10); // 3
return 0;
}
注意事项
- 先 * / %,后 + -。
- 除法
- 两整数相除,结果整数(舍小数部分)
- 两浮点数相除,结果 double 浮点数
- 整数和实数相除,自动类型转换为实型
- 不允许 除 0(与数学一样)
- 取模(取余)
- 运算数必须是整型
- 对负数取余,结果为余数的绝对值
- 不允许 除 0(与数学一样)
// 目标: 掌握算术运算符使用特性
int main(void)
{
// 先乘除后加减
printf("%d\n", 4 + 6 % 5); // 5
// 两整数相除,结果整数(舍小数部分)
printf("%d\n", 19 / 10); // 1
// 两浮点数相除,结果 double 浮点数, 默认保留 6 位小数
printf("%lf\n", 3.6 / 1.3); // 2.769231
// 整数和实数相除,自动类型转换为实型
printf("%lf, %llu\n", 6 / 2.0, sizeof(6/2.0)); // 表达式结果占 8 字节, double 类型.
// 除 0 不允许
printf("%d\n", 6 / 0); // 被零除或对零取余 错误.
// 取余运算,参与运算的操作数,必须为整数
printf("%d\n", 7.3 % 2); // 表达式必须包含整数 错误.
// 对负数取余,结果为余数的绝对值
printf("%d\n", 7 % -5); // 2
// 对 0 取余不允许
printf("%d\n", 6 % 0); // 被零除或对零取模 错误.
return 0;
}
总结
算数运算符有哪些?
- 先 * / %,后 + -。
/ 运算注意什么?
- 两整数相除得整数。 运算表达式遵循类型转换规则
% 运算注意什么?
- 运算数必须是整数。 负数取余结果为正。
2. 比较运算符
基础语法
运算符 | 作用 | 示例 | 结果 |
---|---|---|---|
< | 判断 小于 | 4 < 3 | 不成立(假):0 |
<= | 判断 小于或等于 | 4 <= 3 | 不成立(假):0 |
> | 判断 大于 | 4 > 3 | 成立(真):1 |
>= | 判断 大于或等于 | 4 >= 4 | 成立(真):1 |
== | 判断 相等 | 4 == 3 | 不成立(假):0 |
!= | 判断 不相等 | 4 != 3 | 成立(真):1 |
**注意:**判断 “相等”,使用 “==”, 不能使用 “=”(赋值符)
优先级
- 整体,比算术运算符 低。
- 整体,比赋值运算符 高。
- > >= < <= 高于 == !=
// 目标: 掌握 比较运算符语法 和 优先级
int main(void)
{
// 成立 1, 不成立 0
printf("10 > 10: %d\n", 10 > 10);
printf("10 >= 10: %d\n", 10 >= 10);
int a = 10;
printf("10 <= a: %d\n", 10 <= a);
printf("10 < a: %d\n", 10 < a);
printf("a != 10: %d\n", a != 10);
printf("a == 10: %d\n", a == 10); // 不要将 == 错写成 =
// 整体,低于 算术运算符
printf("a >= 3 + 7: %d\n", a >= 3 + 7); // 先算 +, 再判断 >=
printf("7 == 3 + 4: %d\n", 7 == 3 + 4); // 先算 +, 再判断 =
// 整体, 高于 赋值运算符
int b;
b = 4 > a; // 先算 4 > a, 再赋值
printf("b = %d\n", b);
printf("b = %d\n", b = 7 != a); // 先算 7 != a, 再赋值.
printf("b = %d\n", b = 7 != a + 1); // 先算 a+1, 再判断 7 != a+1, 再赋值.
// > >= < <= 高于 == !=
printf("%d\n", 7 > 5 != 3 <= 4);
return 0;
}
总结
- 关系运算的比较结果只有两种:1(成立、真)、0(不成立、假)
- 计算机中判等,需使用 “==”
- 优先级,高于赋值,低于算数。 > >= < <= 高于 == !=
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; |
**注意:**赋值运算符,会修改变量的原始值。 赋值符左侧,必须可修改(变量)。
int main(void)
{
// = 赋值符, 自右向左
int a = 2, b = 1, c = 0;
a = a + b;
printf("a = %d\n", a);
b = a < c;
printf("b = %d\n", b); // 直接 打印 b = a < c
a = b = c = 8;
printf("a = %d, b = %d, c = %d\n", a, b, c);
// += -= 复合赋值符。需求:微信钱包有 15.8 元, 发 2.9 元红包,收 13.6 元红包。
double money;
money = 15.8;
money += 2.9; // 等价于: money = money + 2.9;
printf("money = %lf\n", money);
// 需求: 发红包
money -= 13.6; // 等价于: money = money - 13.6;
printf("money = %lf\n", money);
// 其他 复合赋值符。
int i, j;
i = 10, j = 5;
//i *= j; // 等价于:i = i * j;
//i /= j; // 等价与:i = i / j;
//i %= j; // 等价与:i = i % j;
printf("i = %d\n", i);
// 思考:
i %= j - 2; // 等价于 i = i % (j - 2); %= 右侧看做一个整体.
printf("i = %d\n", i);
// 注意:赋值符,左侧必须可修改
3 += 2;
return 0;
}
总结
- 先运算,后赋值。方向,自右向左
- += 可实现累加,将别人的数据累加给自己。
- 所有赋值运算符,都会修改变量原始值。
4. 自增减运算符
目标:实现数据的增 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; |
自增自减语法
++ 对变量值 +1。 – 对变量值 -1。
// 目标: 掌握 ++ 自增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;
}
前缀后缀区别
注意:++ 和 – 如果 不是单独使用(如:用在表达式中),前缀和后缀 差异巨大
-
放在变量前,先 +1、-1 再取值使用。
int a = 10; int res = ++a; // 先 +1,再取 a 值给 res。 (先加再用)
-
放在变量后,先 取值用,再 +1、-1
int b = 10; int res2 = b--; // 先取 b 值给 res2, 而后 b 再 -1 (先用再减)
代码验证:
// 目标: 掌握 ++/-- 前缀后缀差异
int main(void)
{
int a = 10;
int res = ++a; // 先+1,再用
printf("res = %d\n", res);
int b = 10;
//printf("b = %d\n", b--); // 先用,再-1
printf("b = %d\n", --b); // 先-1,再用
printf("b = %d\n", b); // 查看b值
return 0;
}
注意事项
- 不能用于常量
- 不能用于表达式
- 优先级:整体高于算数运算符(必然高于比较、赋值);后缀高于前缀
- 不要在一个表达式中,对同一变量 多次 ++、-- 运算。可读性差,且不用编译系统结果不同。
// 目标: 掌握 ++/-- 使用注意事项
int main(void)
{
// 1. 不能用于常量
//printf("%d\n", 10++);
// 2. 不能用于表达式
int a = 10;
// (a - 1)++;
// ++(-a);
// 3. 全部 高于算数运算
//int b = ++a * 3;
int b = a-- * 3;
printf("b = %d\n", b);
// 3. 后缀高于前缀
printf("a = %d\n", -a++);
// 对同一变量 多次 ++、-- 运算。可读性差,且不同编译系统结果不同。
int i = 10;
int j = 5;
int res = i++ + ++i - --j - ++j + 3 + i--;
printf("res = %d\n", res); // 26 --- Linux下gcc编译器: 28
printf("i = %d\n", i); // 11
printf("j = %d\n", j); // 5
return 0;
}
总结
- ++ 自增 1, --自减 1
- 单独使用,前缀后缀没区别;
- 非单独使用:前缀,先+1、-1,再用; 后缀,先用,再+1、-1
- 只适用变量,不能用于常量、表达式。
- 优先级,高于算数、比较、赋值。后缀高于前缀。
5. 逻辑运算符
作用:
- 用程序解决 类似 或者、并且 这种 含有逻辑关系的 情况。
应用场景:
- 去京东买手机。 筛选条件: 128G 并且 120w 快充 。 后台 怎么做? 用 与 运算判断,满足展示,不满足不展示。如果用户 就想买 华为 或者 小米手机,后台用 或 运算,筛选厂商对应的手机。
基础语法
- 将多个条件放在一起运算,最终返回 真(1)或 假(0)
运算符 | 术语 | 示例 | 结果 | 速记 |
---|---|---|---|---|
&& | 与 | 2>1 && 3>2 | &&两边同为真,结果为真,否则为假。 | 同真为真 |
|| | 或 | 2>1||3 > 5 | ||两边有一个为真,结果为真,二者同为假,结果为假。 | 有真为真 |
! | 非 | ! (2>1) | 取反!表达式为假,加 ! 为真;表达式为真,加 ! 为假。 | 真非为假 |
案例1 : 需求,手机存储大于 128,手机屏幕尺寸大于等于 6.35**
// 目标: 掌握逻辑运算符语法特性
int main(void)
{
int storage = 256; // 手机存储
double size = 6.3; // 屏幕尺寸
// 需求1: 手机存储大于128, 同时 屏幕尺寸大于等于6.7
printf("%d\n", storage > 128 && size >= 6.7); // && 同真为真
// 需求2: 手机存储大于128, 或者 屏幕尺寸大于等于6.7
printf("%d\n", storage > 128 || size >= 6.7); // || 有真为真
// !非,取反的意思
printf("%d\n", !6); // 非真为假
printf("%d\n", !0); // 非假为真
printf("%d\n", !(7 < 9)); // 思考结果是什么? --> 0
//(使用时特殊情况)判断 20 是介于 10 和 30 之间的数
// 错误写法
printf("%d\n", 30 > 20 > 10); // C 语言不支持,数学中连续判断的语法
// 正确写法
printf("%d\n", 30 > 20 && 20 > 10);
return 0;
}
案例2 : 判断 20 是介于 30 和 10 之间的数。
// 错误写法
printf("%d\n", 30 > 20 > 10); // C 语言不支持,数学的这种连续判断的语法
// 正确写法
printf("%d\n", 30 > 20 && 20 > 10);
短路运算
逻辑运算符的特性,导致实际应用中一部分表达式不执行,也能得出整个表达式结果。这一特点经常作为考点出现在计算机二级、期末考试题中。
在程序中:
- 判断 表达式 a && (b+c) 的结果:
- 当 a 为假时,不必计算 b+c,可直接得出表达式为假的结论。
- 判断 表达式 a || (b+c) 的结果:
- 当 a 为真时,则不必计算 b+c,就能判断出表达式的值为 真。
**概念:逻辑表达式 运算过程中,只运算左边表达式,就能直接得出整个逻辑表达式的结果。—— 短路运算 **
短路运算作用
在代码中利用短路运算,可 避免不必要运算,提高程序执行效率。 比如有如下代码:
int a = 5, b = 28;
int c = (a > 3) || ((b / 7)*4 % 2 != 0)
printf("c = %d\n", c);
现要计算 c 值。= 右侧表达式含有逻辑或 || 运算符,运算特性 有真为真。|| 左边表达式很容易判断为 真,可确定整个表达式结果为 真。 右侧 b 相关的 复杂表达式 不需要计算 。
短路运算特性
左表达式能直接得逻辑表达式结果,右表达式不执行。
**案例 1:**以下代码执行后,a、b、c 的值依次是多少?
// 目标: 掌握运算特性
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 的值分别是什么?
// 目标: 掌握运算特性
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–,输出结果为何?
// 目标: 掌握运算特性
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
小知识:合理利用短路运算特性,提高程序执行效率
- 编写含**&&**表达式时,&& 同真为真,左表达式值为假时,右表达式不计算, 建议将 易假 值放左边。
- 编写含**||**表达式时,|| 有真为真,左表达式值为真时,右表达式不计算。 建议将 易真 值放左边。
总结
- &&:同真为真; ||:有真为真; ! :真非为假
- 判断一个数在另两个数范围内,用 && 实现
- 短路特性:运算符左侧表达式可直接得结论,则右侧表达式不执行
- 利用短路特性:&&,将易假表达式放左侧;||,将易真表达式放左侧
6. 条件运算符
基础语法
语法:表达式1 ?表达式 2:表达式 3
- 表达式 1 一定起 判别 作用。表达式 2 和 表达式 3 只能有一个执行。
- 三目运算的结果,必须被使用。
运算规则:
-
判断 表达式 1 的结果:
-
为真,整个三目运算的结果为 表达式 2
-
为假,整个三目运算的结果为 表达式 3
-
能解决什么问题呢?比如,查询成绩系统中,根据成绩判定是否及格?可以用 三目运算来进行判断。
案例 1:接收学生成绩,判断是否 及格,给出 Y/N 结果。**
// 目标: 掌握 三目运算语法特性
int main(void)
{
double score;
printf("请输入成绩:");
scanf("%lf", &score);
char res = score >= 60 ? 'Y' : 'N'; // 三目运算结果 赋值给 res 变量
printf("是否及格? %c\n", res);
return 0;
}
案例 2:找出两个数中的较小值
// 目标: 掌握 三目运算语法特性
int main(void)
{
int a = 10;
int b = 20;
printf("较小值为:%d\n", a < b ? a : b); // 三目运算结果在 printf 中使用
return 0;
}
特性和嵌套应用
嵌套条件运算符的写法,在实际编程中较少见,因为代码可读性低。 但,计算机考试中,经常出做考点。
辨别技巧是,当 表达式中 有 2 个以上问号、冒号,一定是发生了 三目运算嵌套。
处理方法是,先将位于右边的 “?” 与它后面最近一个 “:” 配对。因为,条件运算符的结合性,自右向左。
优先级,高于赋值运算符,低于算数、逻辑、比较运算符。
案例 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:
int res = a > b ? c > d ? e : f : g // a > b ? (c > d ? e : f ): g
将 右侧的 ?与后面的 :配对,c > d ? e : f 看做一组 三目运算表达式,作为另外一组 三目运算的 表达式 2。
这种嵌套写法,看其他人写的程序时,能看懂即可。我们不要这样写。
总结
-
语法规则:
- 表达式1 ?表达式 2:表达式 3
- 表达式 1 为真,整个取表达式 2; 为假,整个取表达式 3
- 结果必须被使用
-
嵌套三目运算:
- 出现 两个以上 ?: ,说明有嵌套。
- 自右向左,找 “?” 与它后面最近一个 “:” 配对
-
优先级:
- 高于 赋值运算符,低于 算数、逻辑、比较运算符。
验收案例
练习1:分析程序,执行结束后 a、b、res 的值分别是多少?**
int main(void)
{
int a = 3, b = 4, c = 5, d = 6;
int res = a > b ? a++ : c > d ? ++a : b++;
printf("a = %d, b = %d, res = %d\n", a, b, res);
return 0;
}
练习2:使用三目运算符,编写程序实现找出三个数中的最大值。**
// 方法 1:
int main(void)
{
int a = 11;
int b = 22;
int c = 35;
int ab_max = a > b ? a : b;
int max = c > ab_max ? c : ab_max;
printf("abc最大值为:%d\n", max);
return 0;
}
// 方法 2:
int main(void)
{
int a = 1, b = 2, c = 3;
int max = c > (a > b ? a : b) ? c : a > b ? a : b;
printf("abc最大值为:%d\n", max);
return 0;
}
7,逗号运算符
C语言中,逗号也是一种运算符。 用逗号将多个表达式连接起来,组成逗号表达式。一般形式为:
表达式 1,表达式 2,表达式 3,…,表达式 n
如:a+3, b+4, c+5 是一个 逗号表达式。
求解过程是 自左向右 依次求解。 整个逗号表达式的值,为最后一个表达式 n 的值。
逗号运算符的优先级,是所有运算符中最低的。
练习:分析下面代码执行过程。res 值为多少?
int i = 3;
int res = (i++, ++i, i + 5);
printf("res = %d\n", res);
总结
取整个逗号表达式值的做法,在实际编程中不常用到。 但,计算机考试中,经常出做考点。记住两句话就好了:
- 整个逗号表达式的值,为最后一个表达式 的值。
- 逗号运算符优先级最低(比赋值还低)
练习
分析下列程序执行,i 值为多少?
int i, a;
i = (a = 2 * 3, a * 4), a + 6;
printf("%d\n", i); // i 值为 24。 因为优先级的原因,i存储的不是 整个逗号表达式的值。
8,运算符优先级
运算符 | 名称 |
---|---|
[ ] | 数组下标 |
() | 圆括号 |
- | 负号 |
++、– | 自增、自减 windows:先++优于后++ mac、Linux从左到右依次计算 |
& | 取地址运算符 |
! | 逻辑非 |
(类型) | 强制类型转换 |
sizeof | 长度运算符 |
* | 乘 |
/ | 除 |
% | 取余 |
+ | 加 |
- | 减 |
> | 大于 |
>= | 大于等于 |
< | 小于 |
<= | 小于等于 |
== | 等于 |
!= | 不等于 |
&& | 逻辑与 |
|| | 逻辑或 |
? : | 条件运算符 |
= | 赋值运算符 |
/= | 除后赋值 |
*= | 乘后赋值 |
%= | 取余后赋值 |
+= | 加后赋值 |
-= | 减后赋值 |
, | 逗号运算符 |
案例 1: 分析下面代码执行过程。res 值为多少?
int a = 0;
scanf("%d", &a);
int res = a < -10 || a >= 10, a > -10 && a <= 10;
案例 2: 分析下面代码执行过程。res 值为多少?
int x = 0, y = 1;
int res = x++ != !y;
printf("res = %d\n", res);
案例 3: 分析下面代码执行过程。res 值为多少?
int i = 35, a = 3, b = 5, c = 7;
int res = i % 7 == 0 && (a != b && b != c && c != a)