C++ 竞赛教程
指针是 C++ 的核心特性之一,理解指针需要先了解计算机内存的工作方式。引用则是更安全、语法更简洁的变量别名机制。
9.1
计算机的内存就像一排有编号的格子,每个格子都有一个唯一的编号,称为地址。每个变量都占据内存中的一段连续格子。使用 & 取址运算符可以获取变量的首地址:
| 1 | int a = 10; |
| 2 | cout << a; // 输出变量的值:10 |
| 3 | cout << &a; // 输出变量的地址(十六进制,如 0x61fe1c) |
| 内存区域 | 说明 |
|---|---|
| Stack(栈区)重点 | 存放局部变量、函数参数、返回地址等,由编译器自动管理,出作用域自动释放 |
| Heap(堆区)手动管理 | 动态内存分配区域,由程序员手动申请(new)和释放(delete),不释放会内存泄漏 |
| BSS 段 | 存放未显式初始化或初始化为 0 的全局变量和静态变量 |
| Data 段 | 存放已显式初始化的全局变量和静态变量 |
| Text 段(代码区) | 存储程序的机器指令,只读 |
9.2
指针变量存储的是另一个变量的内存地址。通过指针,可以间接访问和修改它所指向的变量。
| 符号 | 出现场景 | 作用 |
|---|---|---|
| & | 变量前(如 &a) |
取址运算符:获取变量的内存地址 |
| * | 声明语句中(如 int *p) |
指针类型声明:声明一个指针变量 |
| * | 使用指针时(如 *p) |
解引用运算符:访问指针所指向的值 |
| 1 | int *p; // 声明:p 是一个指向 int 类型的指针 |
| 2 | int a = 10; |
| 3 | p = &a; // 让 p 指向变量 a(存储 a 的地址) |
| 4 | |
| 5 | cout << p; // 输出 a 的地址(如 0x61fe1c) |
| 6 | cout << *p; // 解引用:输出 p 所指向的值,即 10 |
| 7 | *p = 20; // 通过指针修改 a 的值 |
| 8 | cout << a; // 输出 20(a 被间接修改了) |
nullptr:int *p = nullptr;。这样意外解引用时会立刻崩溃,便于调试,比野指针安全得多。9.3
数组名本身就是一个指向首元素地址的指针常量,可以像指针一样使用。
| 1 | int arr[] = {1,2,3,4,5}; |
| 2 | int *p = arr; // 等同于 p = &arr[0] |
| 3 | |
| 4 | cout << *p; // 输出 1(arr[0]) |
| 5 | cout << *(p+2); // 输出 3(arr[2]) |
| 6 | cout << p[3]; // 输出 4(arr[3],指针可用下标) |
| 7 | |
| 8 | // 用指针遍历数组 |
| 9 | for (int i = 0; i < 5; i++) |
| 10 | cout << *(p + i) << " "; |
| 特性 | 数组名 arr | 指针 p |
|---|---|---|
| 是否可改变指向 | ❌ 常量,不能修改 | ✅ 变量,可重新赋值 |
| + 偏移运算 | ✅ arr + 1 | ✅ p + 1 |
| [ ] 下标访问 | ✅ arr[2] | ✅ p[2] |
p + 1 并不是将地址加 1,而是偏移一个元素的大小(如 int 指针偏移 4 字节)。解引用前务必确保指针指向有效的数组范围,越界访问是未定义行为。9.4
引用是变量的别名,对引用的所有操作等同于直接操作原变量。引用比指针更安全、语法更简洁,声明时必须立即初始化,且绑定后不能再改变。
| 1 | int a = 10; |
| 2 | int &ref = a; // ref 是 a 的引用(别名),必须在声明时初始化 |
| 3 | cout << ref; // 输出 10(和 a 完全一样) |
| 4 | ref = 20; // 修改 ref 等同于修改 a |
| 5 | cout << a; // 输出 20 |
| 6 | |
| 7 | // 引用最常用于函数参数(实现引用传递) |
| 8 | void swap(int &x, int &y) |
| 9 | { |
| 10 | int temp = x; |
| 11 | x = y; |
| 12 | y = temp; |
| 13 | } |
* 解引用访问值。nullptr。* 和 & 操作。
* 解引用。
| 特性 | 指针 | 引用 |
|---|---|---|
| 是否必须初始化 | ❌ 可不初始化(危险) | ✅ 必须在声明时初始化 |
| 能否改变指向 | ✅ 可以随时指向别处 | ❌ 一旦绑定,终生不变 |
| 是否可以为空 | ✅ 可以为 nullptr | ❌ 不能为空 |
| 语法复杂度 | 需要 * 和 & 操作 | 简洁,像普通变量 |
| 适用场景 | 需要灵活改变指向或可为空 | 函数传参、修改原变量 |
&),更安全、代码更简洁。string、结构体)时,用 const 引用 避免拷贝开销。