C++: 作用域与生命周期
最后更新:2026-08-26
变量不是"定义在哪里都能用"。
有些变量只能在某对大括号里用,有些变量能在所有函数里用,还有些变量在函数结束后还能"记住"上次的值。
这就是作用域和生命周期。
1. 作用域(Scope)
作用域就是变量能被访问的范围。
(1) 1.1 三种作用域
| 作用域类型 | 声明位置 | 能被访问的范围 |
|---|---|---|
| 局部作用域 | 函数内部 | 从声明处到函数结束 |
| 全局作用域 | 所有函数外部 | 从声明处到文件结束(其他文件也能用 extern 访问) |
| 块作用域 | 语句块内部(如 if、for) |
从声明处到块结束 |
▶ 示例 1:局部变量 vs 全局变量(难度⭐)
#include <iostream>
int gGlobalVar = 100; // 全局变量
void foo() {
int localVar = 5; // 局部变量
std::cout << "foo: localVar = " << localVar << std::endl;
std::cout << "foo: gGlobalVar = " << gGlobalVar << std::endl;
}
int main() {
foo();
// std::cout << localVar << std::endl; // ❌ 错误:localVar 在 foo 里声明,main 里看不到
std::cout << "main: gGlobalVar = " << gGlobalVar << std::endl; // ✅ 全局变量在哪都能用
return 0;
}
输出:
foo: localVar = 5
foo: gGlobalVar = 100
main: gGlobalVar = 100
💡 重点: 局部变量和全局变量同名时,局部变量优先(就近原则)。
#include <iostream>
int x = 100; // 全局变量
int main() {
int x = 5; // 局部变量(与全局变量同名)
std::cout << "x = " << x << std::endl; // 输出 5(局部变量优先)
std::cout << "::x = " << ::x << std::endl; // 输出 100(用 :: 访问全局变量)
return 0;
}
2. 块作用域
在 if、for、while 等语句块里声明的变量,只能在块里用。
#include <iostream>
int main() {
if (true) {
int blockVar = 5; // 块作用域
std::cout << "块里:blockVar = " << blockVar << std::endl;
}
// std::cout << blockVar << std::endl; // ❌ 错误:blockVar 在块外不存在
return 0;
}
💡 提示: for 循环的循环变量(如 int i = 0)也有块作用域,但 C++11 之后推荐把循环变量声明在 for 里面,这样它的作用域就限制在循环里。
3. 生命周期(Lifetime)
生命周期就是变量从"诞生"到"消亡"的时长。
| 存储类别 | 生命周期 | 作用域 | 关键字 |
|---|---|---|---|
| 自动变量 | 函数调用时诞生,函数结束时消亡 | 局部 | (默认) |
| 静态局部变量 | 程序启动时诞生,程序结束时消亡 | 局部 | static |
| 全局变量 | 程序启动时诞生,程序结束时消亡 | 全局 | (默认) |
| 静态全局变量 | 程序启动时诞生,程序结束时消亡 | 文件内 | static |
(1) 3.1 自动变量(默认)
#include <iostream>
void foo() {
int x = 5; // 自动变量(默认)
std::cout << "x = " << x << std::endl;
x++; // 修改 x
std::cout << "x = " << x << std::endl;
}
int main() {
foo(); // 输出:x = 5, x = 6
foo(); // 输出:x = 5, x = 6(x 重新创建了)
return 0;
}
💡 重点: 自动变量在函数调用时创建,函数结束时销毁。下次再调用函数,变量是重新创建的(值不会保留)。
(2) 3.2 静态局部变量(static)
#include <iostream>
void foo() {
static int x = 5; // 静态局部变量(只初始化一次)
std::cout << "x = " << x << std::endl;
x++; // 修改 x
}
int main() {
foo(); // 输出:x = 5
foo(); // 输出:x = 6(x 保留了上次的值)
foo(); // 输出:x = 7
return 0;
}
💡 重点: static 局部变量只初始化一次,而且函数结束后不会销毁,下次调用函数时,它的值会保留。
4. 全局变量
(1) 4.1 基本用法
#include <iostream>
int gCount = 0; // 全局变量
void increment() {
gCount++; // 修改全局变量
}
int main() {
std::cout << "初始值:gCount = " << gCount << std::endl;
increment();
increment();
std::cout << "调用两次后:gCount = " << gCount << std::endl;
return 0;
}
(2) 4.2 全局变量的优缺点
| 优点 | 缺点 |
|---|---|
| 所有函数都能访问 | 破坏封装性(任何函数都能修改) |
| 不用传参数 | 让程序难以理解(不知道谁改了它) |
| 多线程时需要加锁(后面会学) |
💡 建议: 尽量避免用全局变量!如果多个函数需要共享数据,用参数传递。
5. 静态全局变量
(1) 5.1 基本用法
// file1.cpp
static int sFileVar = 5; // 静态全局变量(只能在 file1.cpp 里用)
// file2.cpp
extern int sFileVar; // ❌ 错误:file2.cpp 看不到 sFileVar
💡 重点: static 全局变量只能在当前文件里用,其他文件无法通过 extern 访问。这能避免命名冲突。
6. 实战:计数器函数
▶ 示例 2:用静态局部变量实现计数器(难度⭐⭐)
#include <iostream>
int getCount() {
static int count = 0; // 静态局部变量
count++;
return count;
}
int main() {
std::cout << "第 " << getCount() << " 次调用" << std::endl;
std::cout << "第 " << getCount() << " 次调用" << std::endl;
std::cout << "第 " << getCount() << " 次调用" << std::endl;
return 0;
}
输出:
第 1 次调用
第 2 次调用
第 3 次调用
💡 提示: 这个技巧常用在"工厂函数"、"单例模式"等场景(后面会学)。
7. 常见错误
(1) 7.1 在作用域外访问变量
错误示例:
#include <iostream>
int main() {
if (true) {
int x = 5;
}
std::cout << x << std::endl; // ❌ 错误:x 在 if 块外不存在
return 0;
}
编译错误信息:
error: 'x' was not declared in this scope
(2) 7.2 忘记写 static
错误示例:
#include <iostream>
void foo() {
int x = 0; // ❌ 忘记写 static
x++;
std::cout << "x = " << x << std::endl;
}
int main() {
foo(); // 输出:x = 1
foo(); // 输出:x = 1(期望是 2)
return 0;
}
▶ 示例 3:局部变量 vs 块作用域变量(难度⭐)
#include <iostream>
int globalX = 100; // 全局变量
int main() {
int x = 10; // main 函数的局部变量
{
int x = 20; // 块作用域变量,遮蔽外层的 x
std::cout << "块内 x = " << x << std::endl;
std::cout << "全局 x = " << globalX << std::endl;
}
std::cout << "块外 x = " << x << std::endl;
return 0;
}
输出:
块内 x = 20
全局 x = 100
块外 x = 10
❓ 常见问题
extern) > - 静态全局变量:只能在当前文件里访问:: 作用域解析运算符。 > > int x = 100; // 全局变量 > > int main() { > int x = 5; // 局部变量 > std::cout << "局部 x = " << x << std::endl; // 5 > std::cout << "全局 x = " << ::x << std::endl; // 100 > return 0; > } >📖 小节
- 作用域是变量能被访问的范围(局部、全局、块)
- 生命周期是变量能存在的时长(自动、静态、全局)
- 局部变量:函数调用时创建,函数结束时销毁
- 静态局部变量(
static):只初始化一次,函数结束后保留值 - 全局变量:所有函数都能访问,但尽量避免用
- 静态全局变量:只能在当前文件里访问
📝 作业
-
基础题 (Difficulty ⭐): 写一个程序,包含:
-
一个全局变量
gTotal -
一个函数
void addToTotal(int x),给gTotal加上x -
在
main里调用addToTotal三次,然后输出gTotal -
进阶题 (Difficulty ⭐⭐): 写一个函数
int getUniqueId(),每次调用返回一个唯一的 ID(从 1 开始,每次加 1)。 -
用静态局部变量实现
-
在
main里调用五次,输出结果 -
挑战题 (Difficulty ⭐⭐⭐): 写一个程序,包含以下函数:
-
void push(int x):把x加入全局数组 -
int pop():从全局数组取出最后一个元素 -
void printStack():打印全局数组的所有元素
用静态全局变量限制数组只能在当前文件里用(把数组声明为 static)。
- 全局变量:文件内所有函数可访问,程序启动到结束
- 局部变量:块内可见,块结束销毁
- 静态局部变量:首次初始化,程序结束时才销毁
- 命名空间用 namespace 定义,避免名字冲突
- using 声明引入特定名字,using 指令引入整个命名空间
8. 🚀 下一步
学会了作用域和生命周期,接下来我们学习 数组与字符串(第15课)—— 处理多个同类型的数据,以及 C++ 的字符串。