C++启蒙课程:第9章  内存模型和名称空间

我们将探索程序的“幕后指挥部”,精细控制变量的生命周期和可见范围!

🎭

生存区的秘密

探索“栈区的临时舞台” (自动) 和“堆区的自由王国” (动态)。

🏛️

静态英雄的永恒契约

认识程序的“永生居民” (static),并管理它们的“户籍” (链接性)。

🛡️

名字的魔法隔离罩

使用“品牌隔离罩” (namespace) 来避免命名冲突,组织代码。

课时一:生存区的秘密:自动与动态

(覆盖知识点 9.1, 9.2.2, 9.2.10)

9.1 “模块化积木” (单独编译)

大型程序被分解为多个文件 (积木),单独编译,最后由“链接超人”组装成一个可执行文件。

file1.cpp
file2.cpp
header.h
program.exe
// header.h (共享蓝图) void func(); // file1.cpp #include "header.h" void func() { ... } // file2.cpp #include "header.h" int main() { func(); }

9.2.2 “栈区的临时舞台” (自动)

函数内的变量 (自动变量) 存在于“栈区”。函数调用时,变量登上舞台;函数结束时,舞台熄灯,变量消失。

int x = 10; (在舞台上)
void func() { // x 是自动变量 // 进入 func() 时创建 int x = 10; } // 离开 func() 时 x 被销毁

9.2.10 “堆区的自由王国” (动态)

`new` 机器人去“自由王国” (堆) 申请内存。这块内存永远存在,直到你手动用 `delete` 释放它。

自由王国 (Heap)
// 申请内存并初始化为 10 int* p_int = new int(10); // 申请内存但不初始化 double* p_double = new double; // 必须手动释放,否则内存泄漏! delete p_int;

课时二:静态英雄的永恒契约

(覆盖知识点 9.2.3 - 9.2.9)

9.2.4 “全局广播站” (外部)

在函数外定义的变量 (global_var) 默认是“全局广播”,所有文件都能用 `extern` 访问它。

File1.cpp: int global_var = 10;
File2.cpp:
// --- file1.cpp --- int global_var = 10; // 定义 // --- file2.cpp --- // 声明:告诉编译器 global_var 在别处 extern int global_var; cout << global_var; // 输出 10

9.2.5 “文件私有电话” (内部)

在函数外使用 `static` 定义的变量 (file_count) 是“私有电话”,只在当前文件可见,别的文件无法访问。

File1.cpp: static int file_count = 5;
File2.cpp:
// --- file1.cpp --- // 内部链接性 static int file_count = 5; // --- file2.cpp --- // extern int file_count; // 错误! // 链接器找不到 file_count

9.2.6 “隐居的忍者” (无链接性)

在函数“内部”使用 `static` 定义的变量,是“隐居的忍者”。外界看不见它,但它**永远存在**,并记住上次调用的状态。

void track_calls() { // 9.2.6 无链接性, 静态持续性 // 只在第一次调用时初始化为 0 static int call_num = 0; call_num++; cout << "Called " << call_num << " times\n"; }

课时三:名字的魔法隔离罩:名称空间

(覆盖知识点 9.3.1 - 9.3.4)

9.3.1 “变量的可见区” (作用域)

内部代码块 {...} 可以定义同名变量,它会“隐藏”外部的同名变量。

int x = 10; (外部)
int x = 99; (内部)
int x = 10; // 外部 x { int x = 99; // 内部 x, 隐藏外部 x cout << x; // 输出 99 } cout << x; // 输出 10

9.3 “品牌隔离罩” (Namespace)

名称空间 🛡️ 像一个“品牌隔离罩”,防止不同工厂的同名产品 (value) 发生冲突。

int value = 1;
int value = 2;
namespace A { int value = 1; } namespace B { int value = 2; } int main() { // 9.3.3 使用 :: 明确访问 cout << A::value; // 输出 1 cout << B::value; // 输出 2 }

9.3.3 访问名称空间的三种方式

`::` (明确指定), `using 声明` (只引入一个), `using 指令` (引入全部)。

💡 互动体验:

📜 代码支撑:

namespace A { void calc() { ... } } namespace B { void calc() { ... } } // 1. 作用域解析 (推荐) A::calc(); // 2. using 声明 (推荐) using B::calc; calc(); // 调用 B::calc // 3. using 指令 (不推荐在全局) using namespace A; using namespace B; // calc(); // 错误!冲突!

编程实践与作业

是时候检验你作为“内存指挥官”的实力了!

练习 1:动态分配与释放

任务:

编写一个函数 `create_array`,使用 `new` 动态分配一个包含 $N$ 个整数的数组。在 `main` 函数中调用该函数,接收指针后,使用 `delete[]` 释放内存。

点击查看参考答案
#include <iostream> using namespace std; int* create_array(int N) { // 9.2.10 动态分配 int * arr = new int[N]; return arr; } int main() { int size = 5; int * p_data = create_array(size); // ... (使用 p_data) ... // 9.2.10 释放数组内存 delete [] p_data; return 0; }
练习 2:静态变量追踪 (9.2.6)

任务:

编写一个程序,演示 `static` 变量(无链接性)如何记住函数调用的次数。

点击查看参考答案
#include <iostream> using namespace std; void track_calls() { // 9.2.6 静态、无链接性变量 // 只在第一次调用时初始化 static int call_count = 0; call_count++; cout << "--- 第 " << call_count << " 次调用 ---" << endl; } int main() { track_calls(50); // 第 1 次 track_calls(60); // 第 2 次 track_calls(70); // 第 3 次 return 0; }
练习 3:名称空间冲突解决 (9.3.3)

任务:

创建两个名称空间 `A` 和 `B`,它们都定义了函数 `calculate()`。在 `main` 中,使用 `::` 和 `using 声明` 分别调用它们。

点击查看参考答案
#include <iostream> namespace A { void calculate() { std::cout << "A 空间计算!" << std::endl; } } namespace B { void calculate() { std::cout << "B 空间计算。" << std::endl; } } int main() { // 9.3.3 方式 1: 作用域解析 A::calculate(); // 9.3.3 方式 2: using 声明 using B::calculate; calculate(); // 调用 B::calculate return 0; }

本章知识点总结与复习

核心概念 解释/功能 关键用法/示例
自动存储局部变量默认持续性,存 于栈区,函数结束时释放。int x;
静态持续性变量在整个程序执行期间存在,未初始化时为 0。static int count;
外部链接性函数外声明,所有文件可见 (`extern` 访问)。int global_var;
内部链接性函数外声明 + `static`,仅当前文件可见。static int file_var;
无链接性代码块内 + `static`,局部可见,生命周期贯穿始终。static int call_count;
动态存储在堆/自由存储区分配,由 `new/delete` 控制。int * p = new int;
名称空间用于组织名称,解决命名冲突。namespace MySpace { ... }
访问名称空间使用 `::`、`using` 声明或 `using` 编译指令。std::cout; using MySpace::func;