3.5 作用域

作用域规则告诉我们一个变量的有效范围,它在哪里创建,在哪里销毁(也就是说,超出了作用域)。变量的有效作用域从它的定义点开始,到和定义变量之前最邻近的开括号配对的第一个闭括号。也就是说,作用域由变量所在的最近一对括号确定。说明如下:

3.5 作用域 - 图1

上面的例子表明什么时候变量是可见的,什么时候变量是不可用的(即变量越出其作用域)。只有在变量的作用域内,才能使用它。作用域可以嵌套,即在一对大括号里面有其他的大括号对。嵌套意味着可以在我们所处的作用域内访问外层作用域的一个变量。上面的例子中,变量scp1在所有的作用域内都可用,而scp3只能在最里面的作用域内才可用。

3.5.1 实时定义变量

正如在本章前面提到的那样,定义变量时,C和C++有着显著的区别。这两种语言都要求变量使用前必须定义,但是C(和很多其他的传统过程语言)强制在作用域的开始处就定义所有的变量,以便在编译器创建一个块时,能给所有这些变量分配空间。

读C代码时,进入一个作用域,首先看到的是一个变量的定义块。在块的开始部分声明所有的变量,要求程序员以一种特定的方式写程序,因为语言的实现细节需要这样。大多数人在写代码之前并不知道他们将要使用的所有变量,所以他们必须不停地跳转回块的开头来插入新的变量,这是很不方便的,也会引起错误。这些变量定义对读者来说并没有很多含义,它们实际上只是容易引起混乱,因为它们出现的地方远离使用它们的上下文。

C++(不是C)允许在作用域内的任意地方定义变量,所以可以在正好使用它之前定义。此外,可以在定义变量时对它进行初始化以防止犯某种类型的错误。以这种方式定义变量使得编写代码更容易,减少了在一个作用域内不停地来回跳转造成的问题。因为可以在使用变量的上下文中看到所定义的变量,所以代码更容易理解。同时定义并初始化一个变量是非常重要的。通过使用变量的方式我们可以看到初始化一个变量值的意义。

我们还可以在for循环和while循环的控制表达式内定义变量,在if语句的条件表达式和switch的选择器语句内定义变量。下面是一个显示随时定义变量的例子:

3.5 作用域 - 图2

3.5 作用域 - 图3

在最内层的作用域里,p是在作用域结束之前定义的,所以它只是一个毫无意义的表示(但它表明可以在任何地方定义一个变量)。在外层作用域中的p也是一样的情况。

在for循环的控制表达式中i的定义正是一个在需要的地方定义变量的例子(只能在C++中这样做)。i的作用域是for循环控制的表达式的作用域,所以可以轮到下一次for循环并重新使用i。这是在C++中一个非常方便和常用的用法;i是循环计数器的一个常用名字,我们不必费神取新的名字。

尽管例子表明在while语句、if语句和switch语句中也可以定义变量,但是可能因为语法受到许多限制,这种定义不如在for的表达式中常用。例如,我们不能有任何插入括号。也就是说,不可以写出:

3.5 作用域 - 图4

附加的括号似乎是合理的,并且能做很有用的事,但因为无法使用它们,结果就不像所希望的那样。问题是因为‘!=’比‘=’的优先级高,所以char c最终含有的值是由bool转换为char的。当打印出来时,我们在很多终端上会看到一个笑脸字符。

通常,可以认为在while语句、if语句和switch语句中定义变量的能力是为了完备性,但是惟一使用这种变量定义的地方可能是在for循环中(在那里可能使用得十分频繁)。