5.2.2 数组作为函数参数
C 语言允许将数组作为函数的参数,即可以将数组名作为函数的实参进行传递。在函数一章介绍过,函数的实参与形参的类型要匹配,既然实参是数组,那形参也应该是数组,如何定义一个具有数组类型形参的函数呢?
可以在参数名后面加上中括号的形式,表示该参数是一个数组类型。下面定义一个以数组为参数的函数 printArray:
printArray 函数只有一个参数,由于在参数名 arr 的后面有个中括号,所以参数的类型就表示为 int 类型的数组。需要注意的是,这里使用的是空的中括号,其实在中括号内也可以写一个整数,只不过无论这个整数的值是多少,都没有意义,编译器会忽略它,具体原因后面会介绍。
在函数体内使用了 for 循环语句,它会使循环体被执行 5 次,按照下标值 0~4 的顺序,依次访问数组中的各元素,并将数组元素的值扩大 10 倍,然后通过 printf 语句打印到窗口上。
现在,我们再使用这个 printArray 函数来打印数组 a,完整代码如下:
编译运行该程序,结果如下:
10 20 30 40 50
看到了和之前相同的结果。那使用“数组作为参数”与以前的使用“数组元素作为参数”相比,有什么特殊的地方吗?下面就来仔细分析。
1.值复制的内容
数组作为参数进行传递时,虽然也是值复制方式,但这个值并不是数组中的元素,而是这个数组在内存中的位置。就如例子中,将数组 a 作为实参调用 printArray 函数时,编译器只会将数组 a 的内存位置复制给形参 arr。也就是形参 arr 得到的仅是数组 a 的内存位置,并不是数组 a 的所有元素。由于形参 arr 只能保存数组 a 的内存位置,而无法保存数组 a 的数组元素,因此,形参 arr 不会知道数组 a 中到底有多少个数组元素。所以,形参 arr 在定义时,它后面的中括号只能算是标记符,起到标明参数是数组类型的作用,所以都是使用空的中括号,并不会去填入一个整数,因为它并不能真正地表示数组元素的个数。
2.改变实参
使用 printElement 函数打印数组元素时,形参 e 保存的是数组元素的值,因此,在 printElement 函数中将形参 e 的值扩大 10 倍,不会影响到实参(即数组中的元素)。
在 printArray 函数中,形参 arr 为数组类型,它保存的是数组 a 所在内存位置,因此,在使用“arr[i]”时,会到 arr 所保存的内存位置,去寻找下标为 i 的数组元素。而 arr 所保存的是数组 a 的内存位置,所以找到的就是数组 a 中下标为 i 的数组元素。即“arr[i]”和“a[i]”指的是同一个数组元素。因此,在 printArray 函数中,将“arr[i]”扩大 10 倍,也就是将“a[i]”扩大 10 倍。也就是在 printArray 函数中,隐含地将数组 a 中的元素也改变了。这一点可以通过修改主函数,在调用 printArray 函数语句后,再次打印数组 a 中的元素来验证:
程序运行结果如下:
10 20 30 40 50 Print all elements of array a: 10 20 30 40 50
可见,数组 a 中的元素都已经被扩大了 10 倍。
3.需要数组长度信息
现在再看一下 printArray 函数的定义,在它的函数体中,我们使用了 for 循环语句,循环变量 i 的值为 0~4,使循环体被执行 5 次,当 i 的值为 5 时,循环结束。大家仔细想一下,这会导致什么样的问题呢?
printArray 函数只适合打印长度为 5 的数组。如果数组的长度大于 5,那么使用 printArray 函数只能打印出前 5 个数组元素;反之,如果数组的长度小于 5,那么会更加糟糕,在 printArray 函数中发生了数组的越界访问。
究其原因,是我们使用了固定循环 5 次的 for 循环语句。如果我们能根据数组元素的个数来决定循环执行的次数,就不会出现问题了。
只要 printArray 函数能够获得数组长度的信息,就可以很好地解决这个问题。于是,我们给 printArray 函数添加一个参数,用这个参数来指示数组的长度:
新的 printArray 函数拥有了两个形式参数,第一个参数能够保存数组的内存位置,第二参数能够保存数组的长度。有了这两个信息,我们就可以非常方便地访问数组中的所有元素了。在函数体内的 for 循环语句中,我们把“i < 5”修改为“i < len”。这样就不会让循环体永远执行 5 次,而是能够根据数组的长度来决定循环体的执行次数。
由于 printArray 函数的定义被修改,现在拥有了两个形式参数,所以在调用 printArray 函数的时候也需要给出两个实际参数,例如:
printArray(a, 5);
或是通过 sizeof 运算符来计算出数组长度:
printArray(a, sizeof a / sizeof(int));
这里又使用了 sizeof 运算符,通过数组大小除以数组元素大小的方式,获得了数组元素的个数,即数组长度,然后将其作为 printArray 函数的第二个实参进行调用。
4.并非真正数组
看到了 sizeof 运算符,可能不少人会有“柳暗花明”“恍然大悟”的感觉。其实我们完全不必让 printArray 函数带两个参数,可以在 printArray 函数内使用 sizeof 运算符来计算出数组的长度。
唉!想象很丰满,现实很骨感。若真能这样简单,前面就不必如此地大费周折了。在 printArray 函数中,是无法通过 sizeof 运算符来计算出数组长度的,原因是无法通过 sizeof 运算符获得数组的大小。虽然 printArray 函数中的形参 arr 是数组类型的,但它却并非真正的数组。
如果我们在 printArray 函数中使用 sizeof 运算符来获取形参 arr 的大小,得到的结果会是 4,而并非想象中的 20。
大家想真正弄懂形参 arr 的意义,还需要对指针有一定的了解,数组和指针的关系非常密切。第 6 章会介绍指针,我们就把这些问题放到那儿再讲解吧!现在只需知道,形参 arr 能够保存数组的内存位置,但它并非真正的数组,想要在 printArray 函数中获得数组的长度信息,我们需要单独设置一个参数来进行传递。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论