表达式与基础语句
需要预先学习:
1. 基础表达式
表达式是由运算符和操作数组成的计算单元。最简单的表达式可以是一个变量或一个字面量(如 a、10),复杂的表达式则通过运算符将多个操作数组合起来(如 a + b * 2)。每个表达式在求值后都会产生一个结果值。
在 C++ 中,只要是能产生值的代码片段,都可以看作表达式。
1.1 算数表达式
算术表达式使用算术运算符对数值类型(如 int、float、double)的操作数进行计算。C++ 提供五种基本算术运算符:
| 运算符 | 含义 | 示例 |
|---|---|---|
+ |
加法 | a + b |
- |
减法 | a - b |
* |
乘法 | a * b |
/ |
除法 | a / b |
% |
取模(取余) | a % b |
int a = 10;
int b = 3;
int sum = a + b; // 13
int diff = a - b; // 7
int prod = a * b; // 30
int quot = a / b; // 3
int rem = a % b; // 1
溢出的问题
+、-、* 运算可能导致溢出——计算结果超出了该类型能表示的范围。
int max = 2147483647; // int 能表示的最大值(通常)
int overflow = max + 1; // 溢出有符号整数溢出是未定义行为
对于有符号整数(int、long long 等),溢出属于未定义行为——编译器不保证任何结果,程序可能崩溃、输出奇怪的值,甚至看起来一切"正常"。
注意:不要寄希望于溢出"回绕"(wraparound,即借助取模运算的性质使得当值超出范围时自动回到另一端),它的行为不可预测。编写代码时应确保操作数在安全范围内。
整数除法的截断
整数除法 / 向零取整——直接丢弃小数部分,不是四舍五入:
int a = 7 / 3; // 结果是 2
int b = -7 / 3; // 结果是 -2(向零取整,不是 -3)
// 即使接收变量是 double 类型
// 但是流程是:先计算表达式的值 7/3 -> 2,再将 2 转换为 double 类型
double c = 7 / 3; // 结果是 2.0
取模运算
% 运算符用于获取整数除法的余数。对于任意整数 a(被除数)和 b(除数,b ≠ 0),a % b 的结果满足恒等式:
其中 q 是 a / b 的商(向零取整),r 是 a % b 的余数。
取模运算有两个重要特点:
1. 余数的绝对值总是小于除数的绝对值:
2. 余数的符号与被除数 a 的符号相同:
int r1 = 7 % 3; // 1(被除数 7 为正,余数为正)
int r2 = -7 % 3; // -1(被除数 -7 为负,余数为负)
int r3 = 7 % -3; // 1(被除数 7 为正,余数为正)
int r4 = -7 % -3; // -1(被除数 -7 为负,余数为负)
理解要点:
a % b结果的符号只看被除数a,不看除数b。
1.2 赋值表达式
赋值表达式使用 = 运算符将右侧的值赋给左侧的变量。赋值表达式本身也会产生一个值——就是被赋的那个值,因此可以链式赋值:
int a, b, c;
c = 10;
std::cout << c << std::endl; // 输出 10
std::cout << (b = c) << std::endl; // 输出 10,赋值表达式整体的值是 10
a = b = 20; // 链式赋值,相当于先进行 b = 20,再进行 a = (b = 20)
复合赋值运算符将运算与赋值合并为一步:
| 运算符 | 等价于 |
|---|---|
a += b |
a = a + b |
a -= b |
a = a - b |
a *= b |
a = a * b |
a /= b |
a = a / b |
a %= b |
a = a % b |
2. 语句
语句是 C++ 中最小的独立执行单元,它描述了一个要执行的操作。
2.1 基础语句
C++ 中的语句以分号 ; 结尾。最简单的语句由一个表达式加上分号构成:
int a = 10; // 一个定义变量并赋值的语句
a = a + 1; // 一个赋值语句
; // 一个空语句,什么都不做
空语句就是一个单独的分号,语法上是一条语句但不执行任何操作。它通常用在语言要求有一条语句但逻辑上不需要做任何事的地方(例如空循环体)。
2.2 复合语句(代码块)
复合语句(也叫代码块)是用一对花括号 {} 包裹起来的若干条语句。在语法上,一个复合语句被视为一条语句。
{
int a = 10;
int b = 20;
int c = a + b;
}
代码块是 C++ 中组织代码的基本手段——if、while、for 等控制结构都通过代码块来执行多条语句。你可以在任何允许放置一条语句的地方使用一个代码块。
2.3 变量的作用域
作用域决定了变量在程序的哪个范围内可见、可用。C++ 中,变量的作用域从它的定义点开始,到它所在的最近一对花括号 {} 结束。
你可以把作用域想象成一个栈:
- 进入一个代码块时,其中定义的变量像"压栈"一样出现
- 离开代码块时,这些变量像"弹栈"一样被销毁
- 内层代码块可以访问外层的变量(向上看),但外层不能访问内层的变量
#include <iostream>
int globalVar = 100; // 全局变量,整个文件都可见
int main()
{
int localVar = 10; // 局部变量,只在 main 的大括号内可见
{
int innerVar = 20; // 内层代码块定义的变量
std::cout << localVar; // 可以访问外层变量
std::cout << innerVar; // 可以访问当前层变量
}
std::cout << innerVar; // 错误!innerVar 已离开作用域
return 0;
}
同名变量的覆盖
如果在内层代码块中定义了与外层同名的变量,内层的变量会覆盖外层的同名变量——但这种覆盖只是"屏蔽",不会修改外层变量的值:
int x = 42;
{
int x = 100; // 内层的 x 覆盖(屏蔽)了外层的 x
std::cout << x; // 输出 100
}
std::cout << x; // 输出 42,外层的 x 从未被修改


