From 03ed64cc7b87be3562f77cc9d9ad022f69fad6ac Mon Sep 17 00:00:00 2001 From: xiaoshuaijie <2413704818@qq.com> Date: Thu, 3 Sep 2026 18:37:03 +0800 Subject: [PATCH] =?UTF-8?q?docs(cpp):=20=E8=A1=A5=E5=85=A8=E6=8C=87?= =?UTF-8?q?=E9=92=88=E5=9F=BA=E7=A1=80=E7=BB=83=E4=B9=A0=E7=AD=94=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ch04/01-pointer-basics.md | 113 +++++++++++++++++- 1 file changed, 112 insertions(+), 1 deletion(-) diff --git a/documents/vol1-fundamentals/ch04/01-pointer-basics.md b/documents/vol1-fundamentals/ch04/01-pointer-basics.md index 3feecb66f..4de9de4e9 100644 --- a/documents/vol1-fundamentals/ch04/01-pointer-basics.md +++ b/documents/vol1-fundamentals/ch04/01-pointer-basics.md @@ -303,6 +303,80 @@ x = 100 声明两个 `int` 变量 `a` 和 `b`,打印值和地址,通过指针交换值后再次打印。值变了,地址变了吗?为什么? +::: details 参考答案 + +```cpp +#include +constexpr void swap(int *p1, int *p2) +{ + int temp = *p1; + *p1 = *p2; + *p2 = temp; +} +int main() +{ + int a = 10; + int b = 20; + int *p1 = &a; + int *p2 = &b; + + std::cout << "========== 交换前 ==========" << std::endl; + std::cout << "变量a的值: " << a << std::endl; + std::cout << "变量a的地址: " << p1 << std::endl; + std::cout << "变量b的值: " << b << std::endl; + std::cout << "变量b的地址: " << p2 << std::endl; + + swap(p1, p2); + + std::cout << "\n========== 交换后 ==========" << std::endl; + std::cout << "变量a的值: " << a << std::endl; + std::cout << "变量a的地址: " << p1 << std::endl; + std::cout << "变量b的值: " << b << std::endl; + std::cout << "变量b的地址: " << p2 << std::endl; + + return 0; +} +``` + +编译运行: + +```bash +g++ -std=c++17 -Wall -Wextra main.cpp -o main &&./main +``` + +运行结果: + +```text +========== 交换前 ========== +变量a的值: 10 +变量a的地址: 0x7ffe15dc91b0 +变量b的值: 20 +变量b的地址: 0x7ffe15dc91b4 + +========== 交换后 ========== +变量a的值: 20 +变量a的地址: 0x7ffe15dc91b0 +变量b的值: 10 +变量b的地址: 0x7ffe15dc91b4 +``` + +**关键观察:值变了,地址没变** + +仔细对比输出会发现: +- `a` 的值从 10 变成了 20,但地址始终是 `0x7ffe15dc91b0` +- `b` 的值从 20 变成了 10,但地址始终是 `0x7ffe15dc91b4` + +**为什么地址不会变?** + +变量的地址在它被创建时就确定了——`int a = 10;` 在栈上分配空间时,操作系统和编译器协作为 `a` 分配了一块 4 字节的内存(假设 `int` 是 4 字节),这块内存的起始位置就是 `a` 的地址。这个地址在变量的整个生命周期内都不会改变。 + +`swap` 函数通过指针交换的是**变量存储的内容**(即值),而不是变量本身在内存中的位置。就像两个房子交换了住户,但房子的门牌号不会变——`0x7ffe15dc91b0` 这个"门牌号"永远属于变量 `a`,只是里面的"住户"从 10 换成了 20。 + +这也是指针强大之处的体现:通过地址,我们可以跨越函数边界去修改原始变量的内容,而不需要拷贝整个变量或改变它的内存布局。 + +::: + + ### 练习二:追踪指针的值 先不运行,在纸上追踪结果,再编译验证: @@ -328,9 +402,26 @@ int main() 很多朋友第一次做时会在 `*p = *q` 和 `p = q` 的区别上栽跟头——前者是赋值数据,后者是改变指向。 +::: details 参考答案 + +编译运行: + +```bash +g++ -std=c++17 -Wall -Wextra main.cpp -o main &&./main +``` + +运行结果: + +```text + +``` + +::: + + ### 练习三:修复空指针 bug -下面代码有三个指针相关的 bug,找出并修复: +下面代码有两个指针相关的 bug,找出并修复: ```cpp #include @@ -353,6 +444,26 @@ int main() } ``` +::: details 参考答案 + +```cpp + +``` + +编译运行: + +```bash +g++ -std=c++17 -Wall -Wextra main.cpp -o main &&./main +``` + +运行结果: + +```text + +``` + +::: + ## 小结 这一章从内存地址出发,把指针的核心概念梳理了一遍。`&` 获取地址,指针是存储地址的变量,`*` 解引用指针来读写数据;指针的类型决定了解引用时如何解释内存,但指针本身在 64 位系统上都是 8 字节;`nullptr` 是现代 C++ 表示空指针的正确方式,解引用空指针是未定义行为;`const` 和指针的三种组合控制着数据和指向是否可变;未初始化指针、悬空指针、重复释放是最常见的三类陷阱。