好,我们接下来 再来讨论一下变量的作用范围 那么我们先来熟悉两个概念,局部变量和全局变量 什么叫做局部变量全局变量呢?其实是根据变量在程序中作用范围的不同 来进行划分的。所谓局部变量呢,就是在函数内部 或者某个代码块的内部 所谓代码块就是用大括号括起来的那些代码,那么在函数内或者代码块内,定义的那些变量 那么这个变量呢,只在这个函数或者是代码块之内起作用 那么这样的变量就被称作局部变量 那么跟局部变量相对应的呢 有一些变量啊,它的作用范围呢更大,叫做全局变量 所谓全局变量就是在所有的函数外,定义的那些变量 那么它的作用域呢,是从定义变量的位置开始 一直到这个程序文件的结束 也就是说无论这个程序里头有多少个函数,那么从这个变量定义的那个地方开始 它就会一直在起作用,直到这个文件的结束 那么我们来看一个例子,对照一个例子呢来理解一下。看这个程序 在这个程序里头,首先它有main函数。在main函数的前面呢,我还定义了一个自己的函数 那么在这个函数之前还有一行程序,这行程序呢定义了一个变量 像类似这样来定义的变量,以前我们还没有碰到过 我们以前从来没在函数的外面写过任何东西,那么这行程序呢就写到了函数的外面 它呢,就定义了一个全局变量。好,既然熟悉了这个程序的结构,我们就来看一下 这个程序里头所有变量的作用范围。我们首先来数一下 这个程序里头一共有多少变量。那么刚才我们提到的这个在程序外面进行的变量是第一个 excel number,这是第一个。第二个,实际上是 在excel count 这个函数里头定义的这个score,这是第二个变量 第三个变量呢,是在main函数里头定义的这个score 这是第三个变量,除了这个变量之外还有其他变量没有啊? 还有一个,那就是在for循环里面所定义的这个i,这是第四个变量 那我们分别来看一下这些变量的作用范围 我们先来看这个score。这是我们最熟悉的一种变量了 我们以前写程序的时候总在mian函数里面定义变量。那么这种变量的作用范围也很明确。首先它定义在 main函数的内部,所以说它是一种局部变量 按照刚才的定义的话,它属于一种局部的变量。那它的作用范围呢,应该是这样的 在main函数的里面,从这个变量的定义,一直到main函数的结束 这就是score的一个作用范围 那么跟这个变量相类似的,我们在excel count这个函数里头 也定义了一个形参,形参的作用范围啊就在这个函数的里头 所以说它也属于一种局部变量,所以这个绿色的score,它的作用范围呢 是在excel count这个函数的内部 由此我们看到,虽然两个变量的名字是一样的 但是,他们发挥作用的范围,完全不同 而且他们两个的范围没有任何的交集,也就是说这两个变量 独立起作用,互不干涉。我们再来看最外面定义的这个变量 刚才我们说呢这个变量是属于一个全局变量,那它的作用范围应该是什么呢?既然是全局变量 那就是应该从变量的定义的这一行起一直到文件的结束 所以说它的作用范围是最大的,是excel number作用范围。非常非常大 从它的定义开始一直到这个文件的结束 还有一个变量就是这个小i,这个小i是什么类型的变量呢?根据我们刚才的定义, 那么由于这个i是定义在程序块里头的 所以说这个i也是一个局部变量,那它起作用的范围是什么呢? 就是在这个for循环的范围之内 也就是说,这个i出了这个for循环,它就不起作用了 当然我们以前讨论过,那么关于这个i的作用范围的理解 不同的编译器可能有不同的理解结果,有的编译器会认为这个i是从定义一直到main函数的结束 但是vc2008以后的版本里头,那这个i的作用范围呢都是被局限在for循环的内部 也就是说如果你接下来再想使用一个临时变量i的话,你就必须重新再去定义一个 好,我们稍微做一个总结 从这个图上我们可以看得出来,全局变量的范围实际上是最大的。是从这个 变量定义的这行起,一直到整个文件的结束 这是我们知道的第一条。第二条在函数里面定义的局部变量 是从这个变量的定义开始一直到函数的结束,这是第二条。第三条 有一些变量被定义在代码块里头,比方说这个i,被定义在代码块里头 那么这些变量的作用范围就被限定在这个代码块中 这是第三条。第四条 其实在函数里面我们所定义的形式参数也是一种局部变量 它的作用范围呢就是在这个函数的范围之内,出了这个函数,那么这个变量也不能起作用了 这是关于变量的作用范围 那么作用范围的不同对变量的使用有什么影响呢? 对程序的运行有什么影响呢? 我们下面通过一个例子再来看一下。看这个例子,这是main函数。那么在main函数的外头呢 又定义了一个函数叫做exchange,在所有的函数前面定义了两个变量a和b 我们通过刚才的定义可以知道a和b都是全局变量 然后呢,那么在主函数里头呢,我从键盘上读入了a和b,然后呢我调用函数exchange,在exchange里头呢 检查一下a和b的大小关系,如果a小于b的话我就交换a和b的位置 最后呢在主函数里头我再把a和b都打印出来,这就是这个程序的一个基本的结构 那我请问,你觉得,这个程序的执行结果会是怎样的呢? 那么如果我输入3和5分别给a和b的话,他们会被交换吗? 好,我们来分析一下这个程序的执行过程 假设这是我们的内存空间,那么在程序执行的开始呢 定义了两个全局变量a和b 全部变量被定义在了函数的外面,并且呢,它在这个文件里头 都会起作用,那么,我们应该怎么来想象这个全局变量呢? 我们可以这样来想象一下,它被定义在这个地方,不在任何函数的里头 那么程序执行的时候呢系统给main函数开辟一片内存空间,然后main函数就开始运行 首先呢它运行第一句cin,a和b,这个地方我想请问一下 main函数运行到cin,a和b的时候这个a和b指的是谁啊? 这个时候a和b是不是指的上面的a和b啊,是不是指的它呀 对的,因为上面这个a和b的作用范围是从他们的定义开始一直到文件的结束 所以说在这,这个a和b指的就是全局变量,a和b。那么现在要在main函数的里面 给main函数外面的这个a和b进行赋值。也就是说 在main函数的里头我要伸出一只手来 去改变这个main函数之外的这个a和b 在这我画了一只手,画的不好大家别介意 之所以要画这只手,我就是想给大家一个强烈的概念 就是说当在main函数的里面执行cin,a和b的时候 那么就相当于main函数伸出了一只手,伸到函数的外面 去改变外面的a和b。比方说这个时候呢,我们cin的结果是输入了一个3和5 那么把3给了a,把5给了b,接下来呢main函数继续执行,执行到了exchange a,b 既然它要调用exchange这个函数,正如我们前面讲过的,要在内存空间里面开辟一片区域给这个函数 然后呢这个函数开始执行。首先呢,它要判定一下a和b的大小 请问,这个a和b是指的哪个a和b啊? 是不是也是指的全局变量啊?所以说它要判定一下。一看呢 这个时候a等于3,b等于5,满足a小于b的条件吗? 满足。于是呢,它执行a和b要交换的这个操作 这个时候是对谁去执行这个操作啊? 是不是像刚才一样啊?Exchange 这个函数也伸出了一只手, 对定义在函数之外的这个 a 和 b 去进行了操作啊。 这个时候呢, a 和 b 就被进行了一个互换。啊,a 变成了 5, b 变成了 3 。在完成这个互换之后呢,Exchange 函数就要执行完毕了。 那执行完毕之后呢,它就从内存中消失掉了。 Exchange 这函数消失掉之后,在 exchange 这函数之外的 a 和 b 会不会受影响啊 ? 不会受影响。啊,所以说这个 a 和 b 就被保留下来。当 main 函数里头再去打印 a 和 b 的时候, 它会去打印哪个?是不是又去访问函数之外的这个 a 和 b 啊? 啊,所以说它会打印出来 a=5, b=3。 啊,所以整个程序的执行结果应该是这样的。 啊,输入了 3 和 5,那么打印出来呢, 5 和 3 。啊,这就是整个出来的程序执行结果。 所以说我们可以看到全局变量的作用范围是从全局变量的定义 一直持续到整个文件的结束。啊,在整个的这个范围里头, 任何一个函数都可以去访问这个全局变量。啊,这就是全局变量的含义。 那说到这儿,可能有的同学就想到了一个问题。那万一我定义了一个全局变量 a 和 b ,然后呢,我又想呢,在某个函数里头也定义一个 a 和 b , 那会怎样呢?Ok, 我们就来看一个这样的程序。 看这个程序。这个程序的结构跟刚才的那个程序啊,几乎一模一样。 都是在 main 函数之前定义了一个名字为 exchange 的函数。 那么在这个函数之前呢,我也定义了两个全局变量, a 和 b。啊,a b 呢,都等于0。 所不同的是,在这个 exchange 这个函数里头啊, 我也定义了两个形式参数。啊,我们讲过形式参数就相当于局部变量。 这两个局部变量的名字呢,也叫 a 和 b 。跟外面的全局变量的名字是一样的。 这个时候,可以吗?可以。啊,允许你这样来做。 那允许这样做的时候, 当在 exchange 这函数里头, 我访问到 a 和 b 的时候,我指的到底是 里面的这个 a 和 b 呢, 还是外面的这个 a 和 b 呢? 那当然关于这件事情,作为一个编程语言,必须明确的定义下来。啊,我们来看一下, 编程语言是怎么去定义的。首先,因为在这里定义的 a 和 b 是全局变量, 所以说,这个 a 和 b 的作用范围是从它的定义开始一直持续到整个文件的结束。 那么又由于在这个全局变量 a 和 b 的作用范围之内,你又定义了两个局部变量 a 和 b 。因为这两个 a 和 b 是局部变量,所以说它们两个的作用范围将是 在这个函数的里面。比如说这是它的作用范围, 那现在就有了冲突。外面有一个全局变量, 里面又有两个同名的局部变量。那这种情况怎么处理呢? 很清楚,编程语言清晰的规定, 当全局变量与局部变量同名的时候,那么局部变量将在自己的作用域内有效。 它将屏蔽同名的全局变量。也就是说,虽然在外面定义的 a 和 b , 它的作用范围很大,但是,在局部变量定义的这个范围里面, 局部变量说了算。 抱歉,今天这个,今天这个课程录的真是很艰难啊。 因为我现在在车里面来录,那么刚才两个印度的老兄在车外面 discuss, 一直都 discuss 。那现在呢又有一个冰淇淋车过来。 啊,今天比较热闹。那么, 因为受到条件的限制呢,我也是尽可能的找一些比较安静的地方去录课。 首先不能打扰别人,其实呢我们要保证录课的这个质量。那有的时候啊, 这两者之间还真是鱼与熊掌,难以得兼呢。Ok ,我们等它走过去。 还好,今天没有很多小朋友在。 Ok, 这就是全局变量和局部变量之间的关系。 好,那么在明确了这一点之后啊,我们就来看一下这个程序的执行过程。 这个程序的执行呢,跟刚才的程序,啊,基本雷同,我们来看一下。 当程序运行的时候呢,首先在存储中间里面定义了两个全局变量 a 和 b, 存储值是 0。 然后呢, main 函数开始执行。 在 main 函数的里面首先我们来执行 cin , a 和 b。 那刚才我们讲过,这个 a 和 b , main 函数里头 cin 的时候这个 a 和 b 它只能是指外面的这个 a 和 b。 啊,全局变量。所以说,相当于 main 函数伸出了一只手, 要对外面的 a 和 b 进行操作。这个时候呢,假设我的输入是 3 和 5 。啊,一个 3, 一个 5 。那么接下来呢, main 函数 调用了 exchange 这个函数。 那么它要调用这个函数的话, 立刻在内存里面开辟一片空间给 exchange 函数, 然后由于 exchange 函数里面定义了两个形参 a 和 b ,所以说 就相当于在exchange 的函数里面形成了一个 a 和 b。 而且呢,由于 main 函数在调用的时候啊,向 exchange 函数传递了参数, 也就是说啊,相当于这个 a 的值被 copy 到这里。 这个 b 的值呢, 被 copy 到这里。 Copy 的含义我们刚才已经讲过了。所以说在 exchange 函数里头, a 和 b 的值分别是 3 和 5 。啊,这个时候呢,那 exchange 函数继续往下执行, 因为 3 小於 5, 所以说它们两个要互换位置。 啊,也就是说在 exchange 函数里头, a 和 b 进行了一个互换。 互换完了以后,是不是 exchange 函数就结束啦?啊,就执行完了。 执行完了以后,exchange 函数所在的内存空间就被释放掉了。 烟消云散。 那么在 exchange 执行完了之后呢,那么 main 函数回来继续执行。 执行到 cout , a 和 b。 那这个 a 和 b 指的是哪个 a 和 b 啊? 仍然是外面的这个 a 和 b。 所以说这个时候 main 函数又伸出一只手去拿了 外面的 a 和 b 来把它打印出来。所以整个的这个程序的执行结果是 输入 3 和 5 ,输出也是 3 和 5, 没有任何的改变。 那么通过这个过程啊,我们就可以感受到 全局变量和局部变量之间的关系。大家如果碰到这样的问题的时候呢,啊,可以这样来想象一下, 我相信这个问题就迎刃而解。好,这是关于全局变量和局部变量。