那么接下来呢我们再讨论第四个话题: 数组与函数。其实关于这个
问题之前就一直有同学写信给我来问
说虽然看了好多书但是也仍然不清楚。ok那接下来我们就来
分析一下。我们首先看一个例子。看这个例子。
先看一下这一个例子的结构,有一个主函数,主函数的前面定义了一个
名字为change的函数。这个函数有两个形式参数,a和b。 int型的。我们来看一下主函数。
在主函数里头我首先定义了一个数组,a[2]两个元素,分别是3和5。
然后我利用数组的两个元素a[0]和
a[1],用这两个元素作为参数去调用了函数
change,调用完了以后我再把a[0]和a[1]打印出来。那请问你觉得
这个程序的执行结果会是怎样的呢?很多同学一看就知道了,哎呀这个程序没什么奇怪的。
这个程序跟之前我们所给出的那个程序很接近,以前的程序我在这边定义了
两个变量a和b,而在这儿我只不过把这两个变量变成了数组元素a和b。
一点都没错,这个程序跟我们以前讲过的在
main函数里头传递变量a和b给change的函数的这个程序
一模一样,没什么区别。为了说明这个情况,我们也来简单的过一下这个程序的执行过程。
从main函数开始,在main函数里面我定义了一个数组,
这个数组有两个元素a[0]a[1]被赋值为3和5。
然后我就调用了这个函数change。一调用这个函数在内存里面
生成change函数,并且在change函数的里面定义了两个局部变量a和b。
那么由于main函数在调用change函数的时候把a[0]和a[1]传递给了change函数,所以说a[0]的值
就被copy给了a,a[1]的值就被copy
给了b。既然是copy,那么a[0]
等于3,a[1]也就等于3,a[1]等于5,b也就等于5。
没什么稀奇的。然后change的函数继续往 下执行,执行到a等于30,b等于50。于是
a和b的值变为30和50。
执行完这一句之后怎样啊?change函数就执行完毕了。
而且因为它是void的类型,所以说它不需要返回任何的东西给main函数。
于是change函数在执行完毕之后就消失掉了。
那么消失掉了之后main函数继续往下执行去打印a[0]和a[1]。那a[0]和a[1]
发生变化了吗?没有,a[0]还是原来的a[0],a[1]还是原来的a[1]。
所以说整个这个程序执行完毕之后会打印出来3和5。这就是整个这个程序的执行过程。那么透过这个程序
我们就能看到当我们把数组元素
当作参数传递给某个函数的时候
这个数组元素是不是跟普通的变量没什么区别啊?
没有任何的区别。在这儿这个数组元素就相当于两个变量,那a[0]就相当于某个变量比方说a
那a[1]就相当于某个变量比方说b,没有任何的区别。那么这是数组元素
做函数参数的时候所遇到的情况。
当然这并不是我们讨论的重点。我们接下来讨论一下
数组名做函数参数的时候会怎样?看这个程序。
这个程序跟刚才的程序非常的接近。 那么也是在有一个main函数。main函数前面定义了一个change函数。那么所不同
的是change函数的参数从原来的两个变量变成了这样的一个参数,长成这样子。
可以吗?可以。这个定义是完全符合语法的。
就是说当你想把一个数组传递给某一个函数的时候,
就请你按照如此的方式来定义这个函数的形式参数。这样的话
它就可以接受一个数组了。ok所以说在这儿我就定义了一个int
a,后面两个方括号。
方括号里面可以不写东西。ok我们来看一下这个程序。从main函数开始,在main函数里头
我定义了一个数组a[2],赋初值3和5。然后
我利用数组a调用了函数change。
作为这个形式。你看你在这儿定义的是int
a,然后方括号。
然后在这儿我去调用这个函数的时候我给这个函数传
参数,也是直接用了一个数组的名字 a,这个a是在这儿定义的。
通过这种方式调用函数change。调用结束之后我再把a[0]和a[1]的值打印出来。
那么这个程序在你看来它的执行结果会是怎样的呢?
好那我们就先来看一下这个程序的
执行结果。这个程序的执行结果是这样的。 30
50,也就是说原来a[0]和a[1]的值是
3和5 ,但打印出来之后变成了30和50。
也就是说数组元素的值被改变了。 为什么数组元素的值被改变了呢?
这跟我们以前碰到的情况不太一样。
那下面我们就来分析一下。那我首先来分析一下
当函数调用的时候参数传递的情况。
假设说这个蓝色的区域是一片内存空间。当函数开始执行的时候首先开辟一片内存区域
给main函数,main函数里面定义了一个数组a,包含两个元素。
然后main函数用数组a做参数,调用了函数change。
它一调用这个函数那么在内存里面再开辟一片空间把change的函数放进去。
那在这个函数的里面我定义了一个变量来接纳一个数组。
当然我们在这儿讲过很多遍了,虽然它的名字也是a,但是这个a跟这个a的
作用范围完全不同对不对?这个灰色的a的作用范围只是在函数的里面。
这个a[2]的作用范围是在main函数里面。好它两个完全不同。
那么这个时候main函数要把这个参数a传递给这个函数。
那这个传递的过程是怎么去进行的呢?仍然是
copy。仍然是copy。
只是所不同的是在这儿我要特别强调,我们要看一下
它copy的是一个什么东西呀?也就是说这个a是个什么东西?
我们可以看到这个a是数组的名字。
是数组的一个名字。我在这儿需要特别特别强调。
特别特别强调。数组的名字它不是一个变量。
数组的名字不是变量,它是一个常量。
也就是所有数组的名字跟 你写出来的3写出来的5这样的数字一样,它是一个常量。
而不是一个变量。
所以说你在这写一个a不相当于比方你在这里写了一个3或者写了一个5。
那当你去调用一个函数写了一个3和5的时候你都很清楚,它是把这个3的值直接copy给了这个变量对不对?
把这个3的值直接给了这个变量。写5的话就把5的值直接给这个变量。那你现在写的是个a,这个a
跟3和5一样它是个常量,所以说它是直接把这个a的值直接就给了这个a。
ok总结一下,当我们把一个数组
的名字当作实际参数传递给另外一个函数的时候
实际上因为这个数组的名字是一个常量 而不是一个变量,
所以说这种情况跟传个3传个5传任何一个这种数
是一样的。这是我们需要特别清楚的第一点。
那有的同学可能就要问了。那这个数
到底是个什么样的数呢?它代表一个什么含义呢?
那么在这儿我需要强调的第二点其实这件事情 在我们讲数组的时候我们就曾经讲到过
数组的名字其实代表着数组的地址。
什么叫做数组的地址啊?那当然关于地址这个概念我们讲到指针那部分的那个时候
我们还会给出明确的定义。那在这儿你怎么理解呢?
数组的地址就代表着这个数组所在的那个地方。
ok理解不了没关系,我们下面看一下这个例子的运行过程你就清楚了。
这个呢,是刚才我们看到的这个程序。 那么要运行这个程序的话,那么首先在内存空间中开辟
一片区域。啊,把main函数放进去。那么在main函数的里面,
我定义了一个数组。那么想像一下的话,就因该在main 函数
的里面有一片小的空间。啊,这个空间里面呢,定义了一个数组。
然后呢,main函数以数组名作为参数,调用了change
这个函数。那么一调用呢, 就在内存空间中开辟一片新的区域,把change函数放
进去。那么在change函数里头呢,也有一个形式参数,
用来接纳main函数传进来的这个数组的名字。
那刚才我们讲过,数组的名字应该是什么呢?
是代表着数组的地址。也就是说,实际上main函数把这个
数组所在的这片内存空间的地址告诉了
change函数。那么接下来呢,change函数再去对这片地址空间中的
a[0] 和 a[1] 去访问。那就相当于change函
数伸出了一只手,到 main函数的里面
去修改了main函数里面的这个数组里面的值。
啊,又把这个数组的值从3和5,修改成了30和50。
那么执行完这个操作以后呢,change函数就执行完毕了。
执行完毕以后,change函数就消失掉了。
然后呢,main函数接着往下执行,会去打印a[0]
和 a[1]的值。 这个时候a[0] 和
a[1]的值等于多少啊?是30和50。所以程序运行的结果是
30和50。啊,这是这个程序运
行的结果。ok,下面我们来总结一下,
那么当数组的名字被当作函数的 参数,传递给另外一个函数的时候啊,
这个时候啊,就相当于把这个数组在内存中的地址
直接传递给了这个函数。那这是一件非常非常严重的事情。我打个比方,
比方说啊,我有一批金币,相当
值钱的金币,我把它埋在了一个地方了。
这批金币呢,就相当于我所定义的这个数组。那么埋藏金币的这个地点呢,
就相当于这个数组在内存中的那个空间。那现在呢,main函数把这个地址呀,
给了change这个函数。比方说,我是main函数,你是change函数的话,
我呢,把埋藏金币的这个地址告诉了你。啊,比方说我告诉你我就
埋在未名湖边上离翻尾石鱼最近的那一棵树的
下面了。我只要把这个地址告诉了你,
是不是你就可以直接去取那些金币了?
如果到明天我去看,哎哟,那金币全没了,也没问题,因为我告
诉了你了地址。你知道了这个地址之后,你就可以去
访问这片地址里面的东西了。所以说,传递
地址啊,是一件非常严重的事情。那这个事情呢,也就解释了
当main函数把数组a的地址传递给了change函数的时候,
change函数就可以伸出一只手到main函数
的里面去修改这片地址空间里面的
东西了。这就是当你把数组名当作参数,传递给另外一个
函数的时候,你,这个是一个等级相当高的一个授权。
所以说在这种情况下,change函数的任何操作,都是对这个数组实际
存储空间的操作。啊,所以说它才会改变这个数组的值。
这就是数组名做函数参数的时候,我们特别要小心的。在这儿我特别
特别想要申明一下,刚才我们讲的数组名做函数参数的这个过程你听不懂,完全没问题。
因为等到指针的部分,我们还会翻过来,从新地在另外一个高度上
再去解释这个问题。到那个时候你把它学会,就ok了。啊,不要着急。
就是说在这儿听不懂的话,不要着急,没关系。ok,这是关于
数组做函数参数的情况。