今天来谈一谈C语言中传值调用和传址调用的区别。
接下来用一个题目来展开讨论,题目是:写一个函数可以交换两个整形变量的内容。
假设现在有两个变量一个是a,一个是b,现在要交换这两个变量的值,首先我们写出以下程序,然后自定义一个Swap函数,依赖这个函数把两个变量进行交换,现在先把a和b传参,然后在函数调用之前先打印("交换前:a=%d b=%d", a , b),在Swap函数调用后打印("交换后:a=%d b=%d", a , b),程序编写如下:
现在就开始在主函数前先定义这个Swap函数,现在要把一个整型a和一个整型b传进去Swap函数里,所以,Swap对应的也是两个整型参数,我们设为 int x 和 int y ,此处题目只是需要我们交换两个数的内容,也不是需要返回两个数之和,两个数之积之类的数据,所以不用返回,这里就给到 void Swap不用其返回即可。我们知道,交换两个变量需要引入第三个变量,所以此处创建一个变量 z,先把 x 放入 z 中,x 空了,接着把 y 放入 x 中,y 空了之后最后把之前存有 x 值的 z 放入 y 中最后完成两个值的交换,程序编写如下:
现在来测试一下, 输入10和20两个值,程序运行如下:
由上图中可以很明显的发现一个问题,就是交换前和交换后的值一模一样,说明代码出问题了,虽然没有出错,但是逻辑上是有问题的,所以此处我们用F10调试按钮看看到底是哪里出了错,当程序走到Swap (a,b);的这一步时候,打开监视窗口,输入a,b两个值,可以从监视窗口看到就是我们输入的10和20,为了更细致的观察这两个数的值,我们这里再用到&a和&b,最后从监视窗口可以看到如下图的结果:
此时我们再按F11跳入Swap函数里继续监视,这一次我们要观察的两个数就是 x 和 y,所以和刚才的操作一样,我们要在右侧监视输入 x 和 y,还有 &x 和 &y,结果如下图所示:
从上图中可以看到,这里的 x 和 y 的地址和传进来的 a ,b 有所差异,这就证明了一点,只要进到Swap函数里面,又单独为 x 和 y 开辟了空间,从地址上的差异可以知道,x 和 y 的所处空间和 a ,b 是完全不一样的空间,只是传进去的数值是相同的,当我们这时候创建的新变量 z 实现了 x 和 y 值的交换后,其实这个过程是完全没有影响到主函数里面的 a 和 b,没有任何联系。这里有一个专业的说法,此题主函数里面的 a 和 b 是叫实参,Swap函数里的 x 和 y 是形参,这里可以得出的一个专业的结论说法就是,当函数调用的时候,实参传给形参,形参其实是实参的一份临时拷贝,所以对形参的修改,不会影响实参。
这里我们重新编写程序,假设刚才上面定义的函数是Swap1(),那么我们这次定义的函数叫Swap2(),要解决刚才Swap1函数内部的 x 和 y 与 a 和 b没有建立任何联系的这个问题,我们就要用到之前学到的知识:指针。我们知道,如果不想用变量本身来改变变量的值,可以通过把变量的地址取出来,存入一个假设名为pa的变量里面,其类型为 int* ,如果要通过 pa 找到这个变量,那么我们就可以写成 *pa 进行解引用操作就可以了,具体例子如下图所示:
这里就可以通过pa来与a建立联系,也能改变其中的值,以此类比,我们就可以把这题的 a 和 b 的地址交给Swap2,那么函数就可以通过地址找到对应的 a 和 b,程序编写如下图:
此时Swap2函数内部就可以与外部的 a 和 b建立起联系, 最后程序运行效果如下图:
总结:如上说到的Swap1函数,是直接把 a 和 b 本身传进去函数,这种把变量本身传入函数从而调用函数的方法叫做传值调用。这种方法对形参的修改不会影响到实参,函数的形参和实参分别占有不同内存块。
再者,如上面用到的Swap2,把 a 和 b 的地址传进去函数,这种方法叫做传址调用,这种方法可以让函数内部和函数外边的变量建立起真正的联系,也就是函数内部可以直接操作函数外部的变量。



