局部变量
本节阅读量:局部变量
函数体中定义的变量称为局部变量(全局变量将在未来章节讨论):
|
|
函数参数通常也被认为是局部变量:
|
|
本课中,将更详细了解局部变量的一些属性。
生命周期
在对象和变量简介中,讨论了变量定义(如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语言标准中取消了此限制。
