欢迎光临
我们一直在努力

05-运算符与表达式:程序的计算逻辑

运算符与表达式:程序的计算逻辑

让程序学会计算

在上一篇文章中,我们学习了数据类型和变量的基本概念。现在,让我们更进一步——学习运算符和表达式。运算符就像是程序的"动词",它们告诉计算机如何处理数据;而表达式则是由运算符和操作数组成的"句子",用来表达计算逻辑。


一、运算符的分类

C语言提供了丰富的运算符,可以分为以下几大类:

类别 运算符 示例
算术运算符 +, -, *, /, % a + b, a % b
关系运算符 >, <, >=, <=, ==, !=a > b, a != 0
逻辑运算符 &&, ||, ! a && b, !flag
赋值运算符 =, +=, -=, *=, /= a = 10, a += 5
位运算符 &, |, ^, ~, <<, >> a & b, a << 2
自增自减运算符++, – a++, ++b
条件运算符 ? : a > b ? a : b
逗号运算符 , a = 1, b = 2


二、算术运算符

2.1 基本算术运算

#include <stdio.h>

int main() {
int a = 10, b = 3;

printf("a = %d, 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("a / b = %d\\n", a / b); // 除法(整数除法)
printf("a %% b = %d\\n", a % b); // 取余(模运算)

return 0;
}

输出结果:

a = 10, b = 3
a + b = 13
a – b = 7
a * b = 30
a / b = 3 // 整数除法,结果取整
a % b = 1 // 10除以3余1

2.2 整数除法与浮点除法

#include <stdio.h>

int main() {
int a = 10, b = 3;
float c = 10.0f, d = 3.0f;

printf("整数除法: %d / %d = %d\\n", a, b, a / b);
printf("浮点除法: %.1f / %.1f = %.6f\\n", c, d, c / d);

// 使用强制转换实现浮点除法
printf("强制转换: %d / %d = %.6f\\n", a, b, (float)a / b);

return 0;
}

输出结果:

整数除法: 10 / 3 = 3
浮点除法: 10.0 / 3.0 = 3.333333
强制转换: 10 / 3 = 3.333333

2.3 取余运算的特性

#include <stdio.h>

int main() {
printf("7 %% 3 = %d\\n", 7 % 3); // 结果: 1
printf("-7 %% 3 = %d\\n", -7 % 3); // 结果: -1
printf("7 %% -3 = %d\\n", 7 % -3); // 结果: 1
printf("-7 %% -3 = %d\\n", -7 % -3); // 结果: -1

return 0;
}

注意:取余运算的结果符号与被除数相同。


三、关系运算符

3.1 比较运算

关系运算符用于比较两个值,返回布尔值(0表示假,非0表示真)。

#include <stdio.h>

int main() {
int a = 10, b = 5;

printf("a > b: %d\\n", a > b); // 1(真)
printf("a < b: %d\\n", a < b); // 0(假)
printf("a >= b: %d\\n", a >= b); // 1(真)
printf("a <= b: %d\\n", a <= b); // 0(假)
printf("a == b: %d\\n", a == b); // 0(假)
printf("a != b: %d\\n", a != b); // 1(真)

return 0;
}

3.2 常见错误:赋值与相等判断

#include <stdio.h>

int main() {
int x = 5;

// 错误:使用了赋值运算符=而不是相等运算符==
if (x = 10) {
printf("x被赋值为10,条件为真\\n");
}

// 正确:使用相等运算符==
if (x == 10) {
printf("x等于10\\n");
} else {
printf("x不等于10,x = %d\\n", x);
}

return 0;
}

输出结果:

x被赋值为10,条件为真
x等于10

提示:为了避免这种错误,可以将常量放在前面:if (10 == x),这样如果误写为=会产生编译错误。


四、逻辑运算符

4.1 逻辑运算的真值表

运算符 含义 真值表
&& 逻辑与 两个操作数都为真时结果为真
||逻辑或 任意一个操作数为真时结果为真
! 逻辑非 取反

4.2 逻辑运算示例

#include <stdio.h>

int main() {
int a = 5, b = 0, c = -3;

// 逻辑与:两个条件都为真
printf("(a > 0) && (b > 0): %d\\n", (a > 0) && (b > 0)); // 0

// 逻辑或:只要有一个为真
printf("(a > 0) || (b > 0): %d\\n", (a > 0) || (b > 0)); // 1

// 逻辑非:取反
printf("!(a > 0): %d\\n", !(a > 0)); // 0
printf("!(b > 0): %d\\n", !(b > 0)); // 1

// 组合逻辑
printf("(a > 0) && (c < 0): %d\\n", (a > 0) && (c < 0)); // 1

return 0;
}

4.3 短路求值

C语言的逻辑运算符支持短路求值:

#include <stdio.h>

int main() {
int a = 5, b = 0;

// 逻辑与的短路求值
// 第一个条件为假,第二个条件不会被执行
if ((a < 0) && (++b > 0)) {
printf("条件为真\\n");
}
printf("b = %d\\n", b); // b = 0,++b没有执行

// 逻辑或的短路求值
// 第一个条件为真,第二个条件不会被执行
if ((a > 0) || (++b > 0)) {
printf("条件为真\\n");
}
printf("b = %d\\n", b); // b = 0,++b仍然没有执行

return 0;
}


五、赋值运算符

5.1 基本赋值

int a = 10; // 直接赋值
int b = a; // 将a的值赋给b

5.2 复合赋值运算符

#include <stdio.h>

int main() {
int a = 10;

a += 5; // 等价于 a = a + 5,结果: 15
printf("a += 5: %d\\n", a);

a -= 3; // 等价于 a = a – 3,结果: 12
printf("a -= 3: %d\\n", a);

a *= 2; // 等价于 a = a * 2,结果: 24
printf("a *= 2: %d\\n", a);

a /= 4; // 等价于 a = a / 4,结果: 6
printf("a /= 4: %d\\n", a);

a %= 4; // 等价于 a = a % 4,结果: 2
printf("a %%= 4: %d\\n", a);

return 0;
}


六、自增自减运算符

6.1 前缀与后缀的区别

#include <stdio.h>

int main() {
int a = 5, b = 5;
int c, d;

// 前缀自增:先加1,再使用
c = ++a;
printf("前缀自增: a = %d, c = %d\\n", a, c); // a=6, c=6

// 后缀自增:先使用,再加1
d = b++;
printf("后缀自增: b = %d, d = %d\\n", b, d); // b=6, d=5

return 0;
}

6.2 在表达式中的注意事项

#include <stdio.h>

int main() {
int x = 5;

// 不要在同一个表达式中多次修改同一个变量
int result = x++ + ++x; // 行为未定义!

printf("x = %d, result = %d\\n", x, result);

return 0;
}

警告:在同一个表达式中多次修改同一个变量会导致未定义行为,不同编译器可能产生不同结果。


七、位运算符

7.1 位运算的基本概念

位运算符直接操作二进制位:

#include <stdio.h>

int main() {
unsigned char a = 0b00111000; // 56
unsigned char b = 0b00011100; // 28

printf("a = %d (0b%08b)\\n", a, a);
printf("b = %d (0b%08b)\\n", b, b);
printf("a & b = %d (0b%08b)\\n", a & b, a & b); // 按位与
printf("a | b = %d (0b%08b)\\n", a | b, a | b); // 按位或
printf("a ^ b = %d (0b%08b)\\n", a ^ b, a ^ b); // 按位异或
printf("~a = %d (0b%08b)\\n", ~a & 0xFF, ~a & 0xFF); // 按位取反
printf("a << 2 = %d (0b%08b)\\n", a << 2, a << 2); // 左移
printf("a >> 2 = %d (0b%08b)\\n", a >> 2, a >> 2); // 右移

return 0;
}

输出结果:

a = 56 (0b00111000)
b = 28 (0b00011100)
a & b = 24 (0b00011000)
a | b = 60 (0b00111100)
a ^ b = 36 (0b00100100)
~a = 199 (0b11000111)
a << 2 = 224 (0b11100000)
a >> 2 = 14 (0b00001110)

7.2 位运算的实用技巧

#include <stdio.h>

int main() {
int x = 10;

// 判断奇偶性
if (x & 1) {
printf("%d 是奇数\\n", x);
} else {
printf("%d 是偶数\\n", x);
}

// 交换两个数(不使用临时变量)
int a = 5, b = 7;
printf("交换前: a = %d, b = %d\\n", a, b);
a = a ^ b;
b = a ^ b;
a = a ^ b;
printf("交换后: a = %d, b = %d\\n", a, b);

// 快速计算2的幂次
printf("2^5 = %d\\n", 1 << 5); // 32

return 0;
}


八、条件运算符(三元运算符)

8.1 语法与使用

#include <stdio.h>

int main() {
int a = 10, b = 20;

// 求最大值
int max = (a > b) ? a : b;
printf("最大值: %d\\n", max); // 20

// 求最小值
int min = (a < b) ? a : b;
printf("最小值: %d\\n", min); // 10

// 判断是否为偶数
printf("%d是%s\\n", a, (a % 2 == 0) ? "偶数" : "奇数"); // 偶数

return 0;
}

8.2 嵌套使用

#include <stdio.h>

int main() {
int score = 85;

char grade = (score >= 90) ? 'A' :
(score >= 80) ? 'B' :
(score >= 70) ? 'C' :
(score >= 60) ? 'D' : 'F';

printf("成绩等级: %c\\n", grade); // B

return 0;
}


九、运算符的优先级与结合性

9.1 优先级表(从高到低)

优先级 运算符 结合性
1 () 左到右
2 !, ~, ++, –, (类型)右到左
3 *, /, % 左到右
4 +, – 左到右
5 <<, >> 左到右
6 <, <=, >, >= 左到右
7 ==, != 左到右
8 & 左到右
9 ^ 左到右
10 | 左到右
11 && 左到右
12 || 左到右
13 ? : 右到左
14 =, +=, -=, … 右到左
15 , 左到右

9.2 优先级示例

#include <stdio.h>

int main() {
int a = 10, b = 3, c = 2;

// 没有括号,按优先级计算
int result1 = a – b * c; // 等价于 a – (b * c) = 10 – 6 = 4
printf("a – b * c = %d\\n", result1);

// 使用括号改变优先级
int result2 = (a – b) * c; // 等价于 (10 – 3) * 2 = 14
printf("(a – b) * c = %d\\n", result2);

// 复合表达式
int x = 5, y = 3;
int result3 = x > y && x + y > 5; // 等价于 (x > y) && ((x + y) > 5)
printf("result3 = %d\\n", result3); // 1

return 0;
}


十、实战练习

练习1:判断闰年

#include <stdio.h>

int main() {
int year;

printf("请输入年份:");
scanf("%d", &year);

// 闰年判断规则:能被4整除但不能被100整除,或能被400整除
int is_leap = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);

if (is_leap) {
printf("%d年是闰年\\n", year);
} else {
printf("%d年不是闰年\\n", year);
}

return 0;
}

练习2:计算BMI指数

#include <stdio.h>

int main() {
float weight, height, bmi;

printf("请输入体重(kg):");
scanf("%f", &weight);

printf("请输入身高(m):");
scanf("%f", &height);

bmi = weight / (height * height);

printf("你的BMI指数为:%.1f\\n", bmi);

// 判断BMI等级
printf("BMI等级:");
if (bmi < 18.5) {
printf("偏瘦\\n");
} else if (bmi < 24) {
printf("正常\\n");
} else if (bmi < 28) {
printf("超重\\n");
} else {
printf("肥胖\\n");
}

return 0;
}

练习3:位运算实现权限控制

#include <stdio.h>

#define READ 1 << 0 // 0b0001
#define WRITE 1 << 1 // 0b0010
#define EXEC 1 << 2 // 0b0100

int main() {
int permission = READ | WRITE; // 0b0011

// 添加执行权限
permission |= EXEC; // 0b0111
printf("添加执行权限后: 0b%04b\\n", permission);

// 移除写权限
permission &= ~WRITE; // 0b0101
printf("移除写权限后: 0b%04b\\n", permission);

// 检查是否有读权限
if (permission & READ) {
printf("有读权限\\n");
}

// 检查是否有写权限
if (permission & WRITE) {
printf("有写权限\\n");
} else {
printf("没有写权限\\n");
}

return 0;
}

思考:位运算为什么适合用于权限控制?


十一、总结与延伸

本节重点回顾

  • 算术运算符:+, -, *, /, %(注意整数除法和取余的特性)
  • 关系运算符:>, <, >=, <=, , !=(注意=和的区别)
  • 逻辑运算符:&&, ||, !(支持短路求值)
  • 赋值运算符:=, +=, -=, *=, /=
  • 自增自减运算符:++, –(前缀和后缀的区别)
  • 位运算符:&, |, ^, ~, <<, >>(直接操作二进制位)
  • 条件运算符:? :(简洁的条件判断)
  • 运算符优先级:使用括号可以改变运算顺序
  • 下节预告

    下一篇文章我们将学习《流程控制:让程序学会做选择》,深入理解if-else、switch等条件语句的使用方法。


    📌 知识点卡片

    • 整数除法会截断小数部分,使用强制转换可以实现浮点除法
    • 取余运算的结果符号与被除数相同
    • 逻辑运算符支持短路求值,可能导致部分表达式不执行
    • 位运算符直接操作二进制位,常用于底层操作和权限控制
    • 三元运算符是唯一的三目运算符,可以简化简单的条件判断
    • 当不确定优先级时,使用括号明确表达意图

    💡 小技巧

    • 用& 1判断奇偶性比取余运算更快
    • 使用<<和>>进行乘除2的幂次运算
    • 将常量放在==前面可以避免误写为=
    • 复杂表达式使用括号提高可读性

    ⚠️ 注意事项

    • 避免在同一表达式中多次修改同一变量
    • 浮点数比较要小心精度问题
    • 位运算操作的是补码形式
    • 负数右移可能是算术右移(符号位扩展)

    如果你对运算符和表达式有任何疑问,欢迎在评论区留言讨论!下一篇见!

    赞(0)
    未经允许不得转载:171主机测评 » 05-运算符与表达式:程序的计算逻辑
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址