运算符

1. 开发中使用的运算符

  • 算术运算符 : 基本数学运算操作
  • 增强版算术运算符 :基于算术运算符优化增强使用
  • 自增自减运算符:针对于变量存储数据自行 + 1 和 - 1 操作,充满了歧义性
  • 关系运算符:判断两端内容是否满足关系要求
  • 逻辑运算符:多条件整合必备内容
  • **位运算符【重点,难点,必会点】: 后续 STM32 学习开发必会知识点 **

2. 算术运算符

2.1 主要内容
+ - * / % = ()

使用要求

  • 先乘除,后加减,有小括号优先处理小括号中的内容
  • 除操作和取余操作,除数不得为 0
  • = 赋值号是将赋值号右侧的数据,赋值给左侧的变量。

取余操作和除操作讲解

16 ÷ 5 = 3 ... 1 # 数学中对应的基本逻辑
# 开发中,如果使用的是 / 运算符
16 / 5 = 3 # 因为操作数都是整数,所有结果也是整数,可以认为是取整。
16.0 / 5 = 3.2 # 任何一个操作数存在浮点类型数据,最终结果也是一个浮点类型。

# 开发中,如果使用的 % 取余运算符
16 % 5 = 1 # 当前操作为取余操作

10 % 12 = 10
10 / 12 = 0
2.2 算术运算符案例代码
#include <stdio.h>

int main(int argc, const char *argv[])
{
	int n1 = 20;
	int n2 = 10;
	
	/*
	 * 1. 变量有且只有在被赋值的情况下才会修改数据
	 * 2. 开发中,需要注意变量在运行过程中的变化
	 */

	n1 = n1 + n2; // n1 = 30  n2 = 10
	n1 = n1 * n2; // n1 = 300 n2 = 10
	n1 = n1 - n2; // n1 = 290 n2 = 10
	n1 = n1 / n2; // n1 = 29  n2 = 10
	n1 = n1 % n2; // n1 = 9   n2 = 10

	printf("n1 = %d, n2 = %d\n", n1, n2);

	return 0;
}

3. 增强版算术运算符

+= -= *= /= %=
# 基于位运算符
^= &= |=
  • += 举例说明

    int n1 = 10;
    int n2 = 20;
    
    n1 = n1 + n2; <==> n1 += n2;
    
  • 增强版算术运算符可以简化代码结构,同时隐含一定的特定功能,可以满足后续开发中类型转换操作

#include <stdio.h>

int main(int argc, const char *argv[])
{
	int n1 = 10;
	int n2 = 20;

	n1 = n1 + n2;
	n1 += n2;

	printf("n1 = %d, n2 = %d\n", n1, n2);

	return 0;
}

4. 自增自减运算符

4.1 使用建议和语法特征

【使用建议】

  • 自增自减运算符是针对于变量进行操作,无法操作常量。
  • 自增自减运算符是对于变量存储数据进行 自增 1 和自减 1 操作,修改变量存储的数据内容
  • 【墙裂建议】自增自减运算符使用 += 1 和 -= 1替换,避免代码中没有必要歧义性。

【语法特征】

  • 自增运算符 ++ 是将变量存储自增 1, 自减运算符 -- 是将变量存储自减 1
  • 自增自减运算符在变量之前,首先完成自增自减操作对变量的数据存储修改,执行完毕之后,提取变量存储数据内容,参与当前代码执行。
  • 自增自减运算符在变量之后,首先提取当前变量存储的数据内容参与代码执行,提取之后立刻执行自增自减操作,修改变量存储数据。
4.2 自增自减运算符案例代码
#include <stdio.h>

int main(int argc, const char *argv[])
{
	int n = 10;

	printf("n++ : %d\n", n++);
	printf("n : %d\n", n);

	printf("++n : %d\n", ++n);
	printf("n : %d\n", n);

	/*
	 * 【墙裂推荐】
	 *  1. 使用 += 1 和 -= 1 替换自增自减运算符
	 *  2. 自增自减运算符单独成行
	 */
	n--;
	--n;

	printf("n : %d\n", n);

	return 0;
}
4.3 面试题
int n = 5;
int ret = n++ * ++n + n-- * --n + (n++ + n--) / --n;

让我们重新仔细分析这段代码,确保每一步的计算都是正确的。

代码

int n = 5;
int ret = n++ * ++n + n-- * --n + (n++ + n--) / --n;

分析步骤

  1. 初始化
    • n = 5
  2. 表达式分解
    • 表达式为:n++ * ++n + n-- * --n + (n++ + n--) / --n
    • 我们需要从左到右逐步计算每个部分的值。
  3. 计算 n++ * ++n
    • n++:先使用 n 的值(5),然后 n 自增为 6。
    • ++nn 自增为 7,然后使用 n 的值(7)。
    • 计算结果:5 * 7 = 35
    • **此时 **n = 7
  4. 计算 n-- * --n
    • n--:先使用 n 的值(7),然后 n 自减为 6。
    • --nn 自减为 5,然后使用 n 的值(5)。
    • 计算结果:7 * 5 = 35
    • **此时 **n = 5
  5. 计算 (n++ + n--) / --n
    • n++:先使用 n 的值(5),然后 n 自增为 6。
    • n--:先使用 n 的值(6),然后 n 自减为 5。
    • --nn 自减为 4,然后使用 n 的值(4)。
    • 计算结果:(5 + 6) / 4 = 11 / 4 = 2(整数除法)
    • **此时 **n = 4
  6. 汇总结果
    • ret = 35 + 35 + 2 = 72

最终结果

  • ret = 72

验证

为了确保计算的正确性,我们可以用以下代码验证:

#include <stdio.h>
​
int main() {
    int n = 5;
    int ret = n++ * ++n + n-- * --n + (n++ + n--) / --n;
    printf("ret = %d\n", ret); // 输出 ret 的值
    return 0;
}

运行结果:

ret = 72

因此,****ret 的最终值是 72,之前的分析是正确的。

5. 关系运算符 【常用】

5.1 基本语法
> < >= <= != 
== # 等值判断
  • 关系运算符是用于判断两端的表达式是否满足关系要求,如果满足,返回结果为真(1),如果不满足,返回结果为假(0)
  • C/C++ 中 非 0 即真
  • C 语言中通常使用整数类型 int 来存储判断结果,C++ 中补充了一个新类型 bool
  • 关系运算符常用于条件判断,条件过滤和条件限制。
5.2 案例代码
#include <stdio.h>

int main(int argc, const char *argv[])
{
	/*
	 * ret ==> result 结果
	 */
	int ret = 5 > 3;
	printf("ret : %d\n", ret); // ret : 1

	ret = 5 < 3;
	printf("ret : %d\n", ret); // ret : 0

	ret = 5 >= 5;
	printf("ret : %d\n", ret); // ret : 1

	ret = 5 <= 10;
	printf("ret : %d\n", ret); // ret : 1

	ret = 5 != 5;
	printf("ret : %d\n", ret); // ret : 0

	ret = 5 == 5;
	printf("ret : %d\n", ret); // ret : 1

	return 0;
}

6.逻辑运算符【常用】

6.1 基本语法

逻辑运算符通有

  • 逻辑与 &&,同真为真,有假【即】假
  • 逻辑或 ||,有真【即】真,同假为假
  • 逻辑非 !,取反,强牛犟

一般会使用逻辑运算符完成条件的组合,从而实现对应的条件过滤,条件判断。

6.2 案例代码
#include <stdio.h>

int main(int argc, const char *argv[])
{
	int ret = 5 > 2 && 5 > 3;
	printf("ret : %d\n", ret); // ret : 1

	ret = 5 > 2 && 5 > 30;
	printf("ret : %d\n", ret); // ret : 0

	ret = 5 > 2 || 5 > 30;
	printf("ret : %d\n", ret); // ret : 1

	ret = 5 > 20 || 5 > 30;
	printf("ret : %d\n", ret); // ret : 0

	/*
	 * C/C++ 中非 0 即真,!5 
	 * 5 数值对应整个表达式而言是一个真
	 * !5 取反操作,得到结果为假 0
	 */
	ret = !5;
	printf("ret : %d\n", ret); // ret : 0

	ret = !0;
	printf("ret : %d\n", ret); // ret : 1

	return 0;
}
6.3 逻辑运算符短路原则

利用逻辑运算符短路原则可以优化条件,根据条件的权重将条件进行排列,使用最少的条件完成整个表达式的判断,提升代码效率。【勿以善小而不为】

案例一: 逻辑与短路原则

  • 逻辑与表达式,如果出现了一个任何一个假条件,整个表达式结果明确为假,计算机为了降低运算逻辑复杂度,直接终止整个表达式运行。从假条件开始,后续的代码不再执行。
int n = 10;
int ret = 10 > 15 && ++n > 3;

ret = 0;
n = 10;

案例二: 逻辑或短路原则

  • 逻辑或表达式,如果出现了一个任何真条件,整个表达是结果已经明确为真,计算机同理考虑降低计算复杂度,提升效率,直接终止整个表达式运行。从真条件开始,后续的代码不再执行。
int n = 10;
int ret = 10 > 5 || ++n > 10000;

ret = 1; 
n = 10;

7. 位运算符【重点,难点,必会点】

  • 目前阶段要求必须学会位运算符语法,熟练掌握。作用后续在 STM32 硬件课程体现。
7.1 基本语法

&:位与,语法要求 同 1 为 1 有 0 则 0

|: 位或,语法要求 有 1 为 1 同 0 则 0

~ : 取反,语法要求 1 变 0 ,0 变 1

05-真实内存的分析结果

^ : 异或