什么是局部变量?
在 2.5 课《局部作用域简介》中,我们引入了“局部变量”这一概念,即定义在函数内部(包含函数形参)的变量。
实际上,C++ 并没有单一属性能够完全界定“局部变量”。相反,局部变量通过一组相互关联的性质区别于其他(非局部)变量。我们将在本节及后续课程中逐一探讨这些性质。
回顾 2.5 课可知,标识符的“作用域”决定了它在源代码中的可见范围。能够访问时,我们称其“在作用域内”;不能访问时,称其“不在作用域内”。作用域是编译期属性;在作用域外使用标识符将导致编译错误。
局部变量具有块作用域
局部变量拥有“块作用域”,即从其定义点开始,直至所在代码块的末尾均处于作用域内。
相关阅读
如需复习代码块,请回顾 7.1 课《复合语句(代码块)》。
int main()
{
int i { 5 }; // i 在此处进入作用域
double d { 4.0 }; // d 在此处进入作用域
return 0;
} // d 和 i 在此处离开作用域
尽管函数形参并非定义于函数体内部,对普通函数而言,可将其视为函数体代码块作用域的一部分。
int max(int x, int y) // x 和 y 在此处进入作用域
{
int max { (x > y) ? x : y }; // max 在此处进入作用域
return max;
} // max、y 和 x 在此处离开作用域
同一作用域内变量名必须唯一
给定作用域内的变量名必须互不相同,否则任何对该名字的引用都会出现歧义。示例:
void someFunction(int x)
{
int x {}; // 与形参 x 同名,编译失败
}
局部变量具有自动存储期
变量的“存储期”(通常简称“期”)决定其创建(实例化)与销毁所遵循的规则。在大多数情况下,存储期直接决定了变量的“生命周期”。
相关阅读
关于生命周期的讨论见 2.5 课。
局部变量具有“自动存储期”:在定义点创建,在所属代码块结束时销毁。因此,局部变量也常被称作“自动变量”。
int main()
{
int i { 5 }; // i 在此处创建并初始化
double d { 4.0 }; // d 在此处创建并初始化
return 0;
} // d 和 i 在此处销毁
嵌套代码块中的局部变量
局部变量可定义于嵌套代码块,其行为与函数体代码块中的局部变量完全一致:
int main() // 外层代码块
{
int x { 5 }; // x 在此处进入作用域并创建
{ // 嵌套代码块
int y { 7 }; // y 在此处进入作用域并创建
} // y 在此处离开作用域并销毁
// y 在此处已不在作用域,无法使用
return 0;
} // x 在此处离开作用域并销毁
变量 y 的作用域仅限于其所在的内层代码块,生命周期亦然。由于 y 不在外层作用域,外层无法访问。
注意:嵌套代码块仍属于外层代码块作用域的一部分,因此外层定义的变量在内层可见:
#include <iostream>
int main()
{ // 外层代码块
int x { 5 }; // x 在此处进入作用域并创建
{ // 嵌套代码块
int y { 7 }; // y 在此处进入作用域并创建
std::cout << x << " + " << y << " = " << x + y << '\n';
} // y 在此处离开作用域并销毁
return 0;
} // x 在此处离开作用域并销毁
局部变量无链接属性
标识符还具有“链接”属性。链接决定同一标识符在不同作用域中的声明是否指向同一对象(或函数)。
局部变量无链接。每个无链接的同名声明均指向独立对象:
int main()
{
int x { 2 }; // 局部变量,无链接
{
int x { 3 }; // 此 x 与前一个 x 不同
}
return 0;
}
作用域与链接的区别:作用域决定单个声明在何处可见;链接决定多个同名声明是否指向同一实体。
相关阅读
同名变量在嵌套块中的行为见 7.5 课《变量遮蔽(名称隐藏)》。
在最受限的作用域内定义变量
若变量仅在内层代码块中使用,应将其定义于该内层块:
#include <iostream>
int main()
{
{
int y { 5 }; // y 仅在此块内使用
std::cout << y << '\n';
} // y 离开作用域并销毁
return 0;
}
限制变量作用域可减少活跃变量数量,降低复杂性,并明确使用位置。
若变量需在外层使用,则必须在外层声明:
#include <iostream>
int main()
{
int y { 5 }; // 在外层声明,因为后续需要
{
int x{};
std::cin >> x;
if (x == 4) y = 4;
}
std::cout << y; // 此处仍需 y
return 0;
}
新手有时会刻意增加嵌套代码块以提前销毁变量。虽然简化了该变量,但整体函数更长、更复杂,得不偿失。若需如此,建议将相关代码提取为独立函数。
最佳实践
在现有最小作用域内定义变量。切勿仅为限制变量作用域而新建代码块。
C++局部变量测验
问题 1
编写程序,要求用户输入两个整数,分别命名为 smaller 和 larger。若用户第二次输入的值较小,则利用代码块与临时变量交换二者。随后输出 smaller 与 larger 的值,并在代码中注释每个变量的销毁点。输出示例:
Enter an integer: 4
Enter a larger integer: 2
Swapping the values
The smaller value is 2
The larger value is 4
问题 2
简述变量作用域、存储期与生命周期的区别;默认情况下,局部变量具有何种作用域与存储期?