需要预先学习:


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 的结果满足恒等式:

a=b×q+ra = b \times q + r

其中 q 是 a / b 的商(向零取整),r 是 a % b 的余数。

取模运算有两个重要特点:

1. 余数的绝对值总是小于除数的绝对值:

0≤∣r∣<∣b∣0 \leq |r| < |b|

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 从未被修改