从1.3节我们已经得知,当CPU执行intx;时,一个名为x的变量就会被创建,那么接下来自然就会问,这个变量什么时候会被销毁(释放占用的内存)呢?
变量的作用域决定了在其生命周期中,谁可以“看见”和使用这个变量。不管是函数参数,还是函数体中声明的变量,都有其作用域。局部变量在定义时被创建,离开作用域后被销毁。
考虑下面的程序:
#include
int add(int x, int y) // x、y在这里被创建
{
// x、y仅在该函数中可见/可用
return x + y;
} // x、y离开此作用域后就会被销毁
int main()
{
int a = 5; // a被创建并初始化
int b = 6; // b被创建并初始化
// a、b仅在此函数中可用
std::cout << add(a, b) << std::endl; // 调用函数add(),令x=a,y=b
return 0;
} // 离开此范围后a、b被销毁
当函数add()被调用时,参量x、y被创建,且仅在函数add()中可见/可用,调用函数结束后就会被销毁。
变量a、b在main()函数中被创建,且仅在main()中可见/可用,main()结束后就会被销毁。
为了强化你的理解,我们来更详细地跟踪程序的执行过程。
- 执行main()函数
- main中的变量a 被创建并被赋值5
- main中的变量b 被创建并被赋值6
- 将a、b作为实参调用函数add()
- add中变量x 被创建并被赋值5
- add中变量y 被创建并被赋值6
- 操作符+将5、6相加得到11
- 将11作为返回值返回给main()
- add的x、y变量被销毁
- main将11打印到控制台
- main向操作系统返回0
- main的a、b变量被销毁
注意如果函数add()被调用两次,x、y就会被创建和销毁两次,在多函数的程序中,变量的创建和销毁是很频繁的。
作用域避免了命名冲突
在上述程序中,变量a、b与x、y是很容易区分的。现在我们再来看这个程序:
#include
int add(int x, int y) // add中x变量被创建
{
return x + y;
} // add中x被销毁
int main()
{
int x = 5; // main的x变量被创建
int y = 6;
std::cout << add(x, y) << std::endl; // main中x的值被传递给add中的x
return 0;
} // main的x被销毁
在这个程序中,我们将a、b的名称改为x、y,程序依然可以正常运行,尽管main()和add()中都有名为x、y的变量。为什么没有产生命名冲突呢?因为main()中x、y的作用域仅在main()函数中,对add()函数是不可见的。add()和main()都不知道对方有与自己变量名称相同的变量。
这样就避免了命名冲突,作用域使得函数无须关心其他函数是如何命名自己的变量的。也避免了一个函数在不经意间(或故意地)更改其他函数中变量的值。
第四章中还会讲到这个话题。
规则:函数的参量与函数体中声明的变量仅对该函数可见。
小测验
下面的程序会输出什么?
#include
void doIt(int x)
{
x = 3;
int y = 4;
std::cout << "doIt: x = " << x << " y = " << y << std::endl;
}
int main()
{
int x = 1;
int y = 2;
std::cout << "main: x = " << x << " y = " << y << std::endl;
doIt(x);
std::cout << "main: x = " << x << " y = " << y << std::endl;
return 0;
}