局部变量
本节阅读量:局部变量
函数体中定义的变量称为局部变量(全局变量将在未来章节讨论):
|
|
函数参数通常也被认为是局部变量:
|
|
本课中,将更详细了解局部变量的一些属性。
生命周期
在对象和变量简介中,我们讨论了变量定义(如int x)——执行该语句时会实例化(创建)变量。与此类似,函数参数在函数被调用时创建和初始化,函数体中的变量在定义处创建和初始化。
例如:
|
|
接下来的问题是,”实例化的变量何时被销毁?”。局部变量在定义它的花括号末尾处,以与创建相反的顺序被销毁(对于函数参数,则在函数末尾销毁)。
|
|
就像人的一生被定义为出生和死亡之间的时间一样,变量实例的生命周期被定义为创建和销毁之间的时间。请注意,变量的创建和销毁发生在程序运行时(称为运行时),而不是在编译时。因此,生命周期是一个运行时属性。
下面是一个稍微复杂的程序,演示了名为x的变量的生命周期:
|
|
上面程序中,x的生命周期从定义处开始,到函数main末尾结束。这包括执行函数doSomething的期间。
对于高级读者
以上关于创建、初始化和销毁的规则是必要保证。也就是说,对象必须在定义点创建和初始化,并在定义对象的花括号末尾之前销毁(或者对于函数参数,在函数末尾销毁)。
实际上,C++规范为编译器提供了很大的灵活性,可以自行决定何时创建和销毁局部变量。为了优化代码,编译器可以提前创建对象,也可以延后销毁对象。通常,局部变量在进入函数时创建,在退出函数时以相反的创建顺序销毁。在以后的课程中讨论调用堆栈时,将更详细地讨论这一点。
局部变量作用域
变量的作用域决定了在源代码中能看到和使用变量的位置。当变量能被看到和使用时,它就在作用域内。当变量不可见、不能被使用时,它就超出了作用域。作用域是编译时属性,使用不在作用域内的变量将导致编译错误。
局部变量的作用域从变量定义点开始,到定义所在的花括号末尾(对于函数参数,到函数的末尾)。这确保了变量不能在定义点之前使用(即使编译器可能在定义点之前就创建了它)。在一个函数中定义的局部变量,其作用域不包括其他任何函数。
下面的程序演示了名为x的变量的作用域:
|
|
上面程序中,变量x在定义点进入作用域,在main函数末尾退出。请注意,即使函数main调用了函数doSomething,变量x在函数doSomething内也不可见。
作用域与生命周期
作用域与生命周期这两个概念,可能会让初学者感到困惑。
变量不在作用域内,意味着代码中无法访问它。上面的示例中,x从其定义点到主函数的末尾都在作用域内。
生命周期代表变量实例化后的实例存活时间。局部变量实例的生命周期在其超出作用域的点结束,因此局部变量在此时被销毁。
处于生命周期内的变量,不一定在对应代码的作用域内。
注意,并不是所有类型的变量实例都在超出作用域时被销毁。在以后的课程中将介绍这些情况。
另一个例子
下面是一个稍微复杂些的例子。请记住,生命周期是运行时属性,作用域是编译时属性。
|
|
参数x和y在调用add函数时创建,只能在函数add中看到/使用,并在add结束时销毁。变量a和b是在函数main中创建的,只能在函数main()中看到/使用,并在main的末尾销毁。
为了加深理解,让我们更详细地分析这个程序。以下事件按顺序发生:
- 执行从main的顶部开始。
- 创建变量a并给定值5。
- 创建变量b并给定值6。
- 使用参数值5和6调用函数add。
- 创建add参数x和y,并分别初始化值5和6。
- 计算表达式x+y以产生值11。
- add将值11返回调用方main。
- y和x被销毁。
- main将11打印到控制台。
- main将0返回到操作系统。
- 变量b和a被销毁。
注意,如果函数add被调用两次,则参数x和y将被创建和销毁两次。在具有许多函数和函数调用的程序中,变量经常被创建和销毁。
不同函数的同名局部变量
在上面的例子中,很容易看出变量a和b是与x和y不同的变量。
考虑以下类似程序:
|
|
在此例中,函数main中变量a和b的名称改为了x和y。程序的编译和运行结果是相同的,即函数main和add都有名为x和y的变量。
首先,即使函数main和add都有名为x和y的变量,但这些变量是不同的。函数main中的x和y与函数add中的x和y没有任何关系——它们只是碰巧名称相同。
其次,在函数main内部时,名称x和y指的是main的局部变量x和y。这些变量只能在main内看到和使用。类似地,在函数add中,名称x和y指的是函数参数x和y,它们只能在add中看到和使用。
简而言之,add和main都不知道另一个函数有同名变量。因为作用域不重叠,编译器总是清楚地知道在什么时候引用的是哪个x和y。
在未来的课程中,将更多地讨论局部作用域和其他类型的作用域。
关键点
函数的参数或局部变量的名称仅在声明它们的函数中可见。这意味着可以在不考虑其他函数中变量名称的情况下命名本函数中的局部变量,有助于保持函数的独立性。
定义局部变量的位置
在现代C++中,函数体中的局部变量应当定义在尽可能靠近其首次使用的位置:
|
|
上面示例中,变量都是在首次使用前定义的。
注
由于较旧、更原始的编译器限制,C语言以前要求在函数顶部定义所有局部变量。使用该样式的等效C++程序如下所示:
|
|
此样式不是最佳的,原因如下:
- 在定义时,这些变量的预期用途并不明显。必须阅读整个函数,才能确定在何处以及如何使用对应的变量。
- 无法在定义时就按预期初始化值(例如,无法将sum初始化为预期值,因为还不知道x和y的值)。
- 变量的初始值设定和它首次使用的位置之间可能相隔很多行。如果不记得它的初始化值,需要回到函数顶部查看,容易分散注意力。
在C99语言标准中取消了此限制。