☰
C++ 第 12 课:局部变量、作用域、变量生命周期
2026/10/2 2:33:05 网站建设 项目流程

上一课标准答案:

  1. result = 7
  2. 返回值类型是double;返回值是45.5
  3. result = false
double error = calculateError(80.0, 50.0);

表示调用calculateError函数,把80.0传给目标值、50.0传给当前值,函数计算后返回30.0,最后把这个结果存进error。


第 12 课:局部变量、作用域、变量生命周期

这一课非常重要。

因为以后你学:

函数 指针 引用 类 栈 动态内存 ROS2

都会碰到一个问题:

这个变量到底在哪里能用?什么时候还存在?

先别急着记专业名词,我们从直觉开始。


1. 先看一个奇怪的问题

void test() { int a = 5; } int main() { std::cout << a << std::endl; return 0; }

你可能觉得:

前面不是已经创建a = 5了吗?

为什么main()里不能直接用?

因为这个:

int a = 5;

是在test()的花括号里面创建的。

它只属于:

test()

这块区域。


2. 用“房间”理解作用域

把函数想象成不同房间。

┌───────────────┐ │ test 房间 │ │ │ │ a = 5 │ │ │ └───────────────┘ ┌───────────────┐ │ main 房间 │ │ │ │ │ └───────────────┘

a放在test房间里。

所以:

test房间里的人能看到a

但是:

main房间里看不到a


3. 这就是“作用域”

专业一点的名字叫:

scope,作用域

意思就是:

一个变量可以被访问的代码范围。

例如:

void test() { int a = 5; std::cout << a << std::endl; }

这里可以使用:

a

因为还在:

{ ... }

这个范围里面。


4. 出了花括号,就不行了

void test() { int a = 5; } std::cout << a << std::endl;

这里:

a

已经离开它的作用范围。

所以程序会报错。

你可以先记:

在{}里面创建的普通局部变量,一般只能在这对{}里面使用。


5. 什么叫局部变量?

例如:

void test() { int a = 5; }

这里的:

a

叫:

局部变量 local variable

“局部”就是:

只属于某个局部范围。


6.main()里的变量也是局部变量

例如:

int main() { int age = 20; return 0; }

age也是局部变量。

它的作用域大致就是:

{ int age = 20; return 0; }

这一块。

不是只有普通函数里的变量才叫局部变量。


7. 不同函数可以有同名变量

看:

void test1() { int a = 5; } void test2() { int a = 10; }

这样是可以的。

为什么?

因为它们在不同的“房间”。

test1 房间 a = 5 test2 房间 a = 10

它们不是同一个变量。


8. 这点特别重要

看:

void functionA() { int angle = 30; } void functionB() { int angle = 60; }

虽然都叫:

angle

但实际上是两个不同的变量。

就像:

张三家有一个“杯子” 李四家也有一个“杯子”

名字一样,不代表是同一个东西。


9. 参数也是局部变量

还记得:

double calculateError(double target, double current) { return target - current; }

这里:

target current

其实也只在:

calculateError

函数内部有效。

它们也属于局部变量。

例如:

int main() { std::cout << target << std::endl; }

这里不能直接使用target。

因为:

target

属于calculateError()。


10. 调用函数时会发生什么?

例如:

double calculateError(double target, double current) { double error = target - current; return error; }

然后:

calculateError(50.0, 20.0);

可以粗略想象成:

进入 calculateError 房间 target = 50 current = 20 error = 30 return 30 离开房间

函数结束后:

target current error

这些局部变量通常就结束它们的生命周期。


11. 什么叫“生命周期”?

作用域和生命周期不是完全一回事,但初学阶段先这样理解:

作用域:

在哪里能使用它?

生命周期:

它什么时候存在?

例如:

void test() { int a = 5; }

调用:

test();

可以粗略理解为:

进入 test ↓ 创建 a ↓ a = 5 ↓ test 执行完 ↓ a 的这次生命结束

12. 再次调用test()呢?

void test() { int a = 5; a++; std::cout << a << std::endl; } int main() { test(); test(); return 0; }

第一次调用:

创建新的 a a = 5 a++ a = 6 输出 6 函数结束

第二次调用:

重新创建一个新的 a a = 5 a++ a = 6 输出 6

所以最终:

6 6

不是:

6 7

这一点非常重要。


13. 为什么不是 7?

因为普通局部变量:

int a = 5;

每次进入函数时都会重新创建。

第一次函数结束以后,那次的a已经结束了。

第二次:

又是一个新的a

所以重新从:

5

开始。


14.if里面也有自己的作用域

看:

int main() { if (true) { int a = 5; std::cout << a << std::endl; } return 0; }

这里:

a

只属于:

if { ... }

这一块。

所以:

int main() { if (true) { int a = 5; } std::cout << a << std::endl; }

这里通常会报错。

因为已经出了a的作用域。


15.for循环里的i呢?

你之前经常写:

for (int i = 0; i < 5; i++) { std::cout << i << std::endl; }

这个:

i

一般只属于这个for循环。

所以:

for (int i = 0; i < 5; i++) { }

结束以后,再写:

std::cout << i << std::endl;

通常就不能用了。


16. 为什么这样设计?

因为如果所有变量在整个程序里都一直存在、到处都能用:

a b angle speed state count error

程序稍微复杂一点就会乱成一团。

函数内部自己管理自己的变量,反而更安全。

比如:

double calculateError(...) { double error; }

另一个函数也可以有:

void checkMotor() { int error; }

互相不冲突。


17. 机器人程序里为什么尤其重要?

假设以后你写:

double calculateJoint1Error() { double error = 10.0; return error; }

另一个函数:

double calculateJoint2Error() { double error = 20.0; return error; }

这里两个:

error

完全可以同时存在。

因为:

Joint1 函数里的 error

和:

Joint2 函数里的 error

不是同一个变量。


18. 但是外层变量可以在内层使用

看:

int main() { int a = 5; if (true) { std::cout << a << std::endl; } return 0; }

这里可以输出:

5

为什么?

因为:

a

在外层:

main

里面创建。

而:

if

在它里面。

可以粗略理解成:

main 大房间 ┌────────────────────┐ │ a = 5 │ │ │ │ if 小房间 │ │ ┌─────────────┐ │ │ │ 可以看到 a │ │ │ └─────────────┘ │ └────────────────────┘

19. 但反过来不行

如果变量是在小房间创建:

int main() { if (true) { int a = 5; } std::cout << a << std::endl; }

外面看不到。

可以想象:

main 大房间 ┌────────────────────┐ │ │ │ if 小房间 │ │ ┌─────────────┐ │ │ │ a = 5 │ │ │ └─────────────┘ │ │ │ │ 外面看不到 a │ └────────────────────┘

20. 一个容易混淆的例子

看:

int main() { int a = 5; if (true) { int a = 10; std::cout << a << std::endl; } std::cout << a << std::endl; return 0; }

你可能会疑惑:

怎么能有两个a?

可以。

因为内层又创建了一个新的局部变量:

int a = 10;

所以可以想成:

外层 a = 5 进入 if ↓ 内层又创建 a = 10 ↓ 内层优先使用自己的 a ↓ 输出 10 离开 if ↓ 内层 a 消失 ↓ 重新看到外层 a = 5 ↓ 输出 5

最终:

10 5

21. 这叫“遮蔽”

专业名字叫:

variable shadowing,变量遮蔽

现在不用背英文。

只要知道:

内层创建了一个同名变量,会暂时把外层那个同名变量“挡住”。

但真实工程里:

通常不建议随便写很多同名变量。

因为很容易看晕。


22. 一个机械臂例子

#include <iostream> double calculateError(double target, double current) { double error = target - current; return error; } int main() { double target = 90.0; double current = 60.0; double error = calculateError(target, current); std::cout << error << std::endl; return 0; }

这里其实存在两套变量。

main()里面:

target current error

函数里面:

target current error

虽然名字一样,但它们属于不同作用域。

调用时只是:

main 的 target 值 ↓ 传给函数的 target main 的 current 值 ↓ 传给函数的 current

不是同一个变量直接“搬进去”。

这个区别以后学值传递、引用、指针时会非常重要。


23. 现在先形成三个概念

局部变量

在某个函数或代码块内部创建的变量。

例如:

int a = 5;

作用域

变量:

在哪里可以被使用。


生命周期

变量:

从什么时候创建,到什么时候结束。


24. 本课最核心的一句话

以后看到:

{ int a = 5; }

你就应该想到:

a属于这一层{}的局部范围,出了这个范围通常就不能再使用。


本课小练习

第 1 题

void test() { int a = 5; } int main() { std::cout << a << std::endl; }

这段代码能正常使用a吗?为什么?

第 2 题

void test() { int a = 5; a++; std::cout << a << std::endl; } int main() { test(); test(); }

输出:

? ?

第 3 题

int main() { int a = 3; if (true) { std::cout << a << std::endl; } }

能不能在if里面使用a?

第 4 题

int main() { if (true) { int b = 10; } std::cout << b << std::endl; }

这里为什么会有问题?

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询