在C语言中,所有参数的传递都是“值”传递,所谓“值”传递是指在函数调用时,系统为形参开辟相应的内存,然后将实参的值复制给形参,完成参数的传递。在参数传递完成后,被调函数中所有针对形参的操作不会影响到实参,因此可以说这种参数传递方式是“单向”的。请运行以下两个程序并对比程序的输出结果。
【例7-3(a)】输入两个整数并求出其最大值。
该程序是同学们非常熟悉的一个求最大值的程序,似乎没有什么问题,主调函数中调用被调函数求出了a和b二者中的最大值。但根据函数的执行过程应该知道,被调函数实质上并不是在求a和b二者的最大值,而是在求x和y的最大值。根据变量的作用域范围,被调函数max也无法直接操作main函数中局部变量a和b,被调函数只是求出了形参x和y的最大值并将此值返回给了主调函数,仅此而已。只是由于形参x和y的值恰恰等于实参a和b的值,从而屏蔽了参数传递过程,给初学者造成了函数调用max(a,b)是在求a和b二者之中最大值的假象,其参数传递过程如图7-4(a)所示。
图7-4 函数的“值”传递
作为一个对比,我们对例7-3(a)稍作修改,请大家对比程序结果。
【例7-3(b)】输入两个整数并求出其最大值。
此程序的输出结果显然不是期望中的a和b二者之间的最大值,其根本原因就在于max函数中对x和y的值进行了修改。在函数调用时,实参a和b的值传递给形参x和y后,x和y中的值确实是20和30,如图7-4(a)所示。但随后执行x=x+30和y=y-30两语句后,x和y中的值就分别被修改成了50和0,如图7-4(b)所示。程序结果是50,说明max函数并不是求出了a和b二者之间的最大值,而是求出了x和y之间的最大值并将该值返回给了主调函数。但是从程序结果也可以看出,形参x和y的值修改为50和0后并没有引起实参a和b的变化,其值仍然是20和30,图7-4(b)中没有箭头线,表示参数传递过程已经结束,此时a、b和x、y都各自有存储单元,x和y无论如何变化,也都和实参a、b没有任何关系。
参数的传递过程是将实参的“值”传递给形参,因此参数传递过程用单向箭头表示,也就是所谓的单向“值”传递,如图7-4(a)所示,其本质是在函数调用发生时,系统给形参x、y开辟内存,然后将实参a、b的值“复制”给了形参,随后结束参数的传递过程。参数传递过程结束后,实参a、b和形参x、y之间再没有关系,因此当被调函数修改形参x、y的值时,再不会对主调函数中的实参产生任何影响。
但是在实际编程过程中可能会遇到这样的需求:在被调函数中修改主调函数中某些变量的值。由以上分析可知,通常情况下被调函数是无法直接操作主调函数中的变量的,如何完成这一需求?
在C语言中,函数的参数不仅可以是整型、实型、字符型等基本的数据类型,还可以是指针类型。当用指针变量作函数参数时,可以将主调函数中某个变量的地址传递到被调函数中,在形参从实参获得了一个变量的地址后,即可按照内存间接访问的方法,修改主调函数中相对应的变量的值。请运行并对比例7-4两个程序的运行结果。
【例7-4(a)】通过函数调用交换主调函数中两个整型变量的值。(www.xing528.com)
变量a和b并没有完成预期中的交换,这就是刚讲述过的参数的单向“值传递”,由于swap函数中交换的是形参x和y的值,因此对主调函数中的实参a和b不会产生影响。下面修改程序中的形参为指针变量,请看例7-4(b)。
【例7-4(b)】通过函数调用交换主调函数中两个整型变量的值。
将形参修改成指针变量后,主调函数中的变量a和b真的发生了交换,而这一交换显然是由被调函数swap来完成的,那么swap函数是如何操作了主调函数中的变量的?参数传递过程如图7-5所示,图中实现箭头表示参数传递,虚线箭头表示指针指向关系。
图7-5 指针作函数参数时的参数传递
从参数传递过程可以看出,由于实参pa和pb中分别存放变量a和变量b的地址,因此*pa和*pb就是变量a、b的间接内存引用形式。形参指针变量x、y分别接收实参指针变量pa、pb的值,从而获得了主调函数中变量a和变量b的地址,根据内存的间接访问方法,则被调函数中的*x和*y也是主调函数中的a和b,因此被调函数中对于*x和*y的交换,就是在交换主调函数中a和b的值。可见若需在被调函数中修改主调函数中的变量,可以通过传递欲修改变量的地址的方法来实现。
需要注意的是,实参指针pa、pb向形参指针x、y传递的仍是一个值,只不过这个值是一个变量的“地址”。也就是说并没有从实质上改变C语言中“传值”参数传递方式,若在参数传递完成后,形参指针x、y发生了改变,这种改变不会对实参指针pa和pb产生影响。请考虑将swap函数做如下修改后,还能否将a和b的值进行交互。
请同学们自己上机验证并分析原因。在例7-4(b)中,由于指针pa、pb保存的就是变量a和变量b的地址,因此可以直接用a、b的地址作实参。
由此可见指针作为函数参数的目的就是:通过内存的间接访问方式,使得被调函数在获得主调函数中某些变量的地址后,可以操作主调函数中的变量。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。