我说编程细节 - 函数参数传递

参数是影响函数输出的决定性要素之一,也是接口设计的要素之一。

怎么样做到合理的接口设计和正确的接口调用呢? 当然必须深刻理解参数的传递过程。

 

通常的参数传递有两种方式: 值传递和地址传递。

通常值传递是一种安全的传递方式,而地址传递则需要做安全性的足够考量。其实这个很好理解,比如一个人问你要身份证复印件办理一些事务,你最好的办法就是复印一份给他,而不是告诉他你的身份证放在某个位置,让他自己拿去复印,这样的安全性你可想而知。

 

正因为如此,不同的语言围绕这两种方式做了针对性的限制,我们先以主流的三种语言(C/C++, C#, Java)来看看是如何操作的。

 

C/C++,由于针对底层操作的便利,完全开放了值传递和地址传递(值,指针,引用)。

C#,强调值传递,重点推荐类地址传递(引用传递),提供特别通道进行地址传递(ref, out)。

Java, 关闭地址传递,只容许类地址传递(引用传递)。

 

说到这里,也许有人有点迷惑了,引用传递不就是地址传递吗?

那么看看在Java里的这么一个函数会发生什么?

static T swap(T a, T b)

{

    int t;

    t = a;

    a = b;

    b = t;

}

 

显然swap(x,y)什么都没有发生,Java不是说全引用传递吗?为什么不能交换呢?

这是因为引用传递实际上也是值拷贝,但这个值拷贝进行得有点意思而已。

那么引用类型到底是怎么进行参数传递的呢?

 

要搞清这个问题,首先,我们必须温习一下什么是形式参数和实际参数?

形式参数是在参数传递过程中用来接受实际参数传递的信息而开辟的临时存储空间。而实际参数是在发生函数调用前已经开辟的存储空间。函数调用是通过栈实现的。

 

值类型变量,通常在栈上;引用类型变量通常在堆上,栈上放置堆地址。

参数传递过程中,形参是拷贝实参的值,那么值类型变量拷贝的是一个副本,形参的变化当然就不能影响到实际参数的变化了。而在引用传递是,形参拷贝的是堆地址的一个副本,所以改变副本本身当然也不会影响到堆空间发生变化,但改变副本空间的值时,就会影响到堆空间发生变化。如图

编程的那些事 <wbr>- <wbr>细说函数参数传递

原来如此,这样就容易解释为何上述Java代码没有任何作用了,如果一定要起作用怎么办呢?C#提供了ref关键字,C++提供了指针传递机制。其实就是改变拷贝的实现,让形参拷贝实参的栈地址,这样任何形参的变化都会直接反映在实参上面。但这样显然是不安全的,所以Java断了这种念想。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值