一. 形参与实参:
形参出现在函数定义中,在整个函数体内都可以使用,离开该函数则不能使用。
实参出现在主调函数中,进入被调函数后,实参变量也不能使用。发生函数调用时,主调函数把实参的值传送给被调函数的形参从而实现主调函数向被调函数的数据传送。
函数的形参和实参具有以下特点:
1. 形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只有在函数内部有效。函数调用结束返回主调函数后则不能再使用该形参变量。
2. 实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使实参获得确定值。
3. 实参和形参在数量上,类型上,顺序上应严格一致,否则会发生类型不匹配”的错误。4. 函数调用中发生的数据传送是单向的。即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。 因此在函数调用过程中,形参的值发生改变,而实参中的值不会变化。
5.当形参和实参不是指针类型时,在该函数运行时,形参和实参是不同的变量,他们在内存中位于不同的位置,形参将实参的内容复制一份,在该函数运行结束的时候形参被释放,而实参内容不会改变。 而如果函数的参数是指针类型变量,在调用该函数的过程中,传给函数的是实参的地址,在函数体内部使用的也是实参的地址,即使用的就是实参本身。所以在函数体内部可以改变实参的值。
二. 值传递与引用传递
1. 值传递:形参是实参的拷贝,改变形参的值并不会影响外部实参的值。从被调用函数的角度来说,值传递是单向的(实参->形参),参数的值只能传入,不能传出。当函数内部需要修改参数,并且不希望这个改变影响调用者时,采用值传递。
2.引用传递: 就是传了内存空间的地址, 行参实参公用一个地址的数据, 当函数内部需要修改参数,也将同时改变影响调用者。
归结起来:
call-by-value方式的调用参数和被调用方法中的参数,是两个变量,代表两个不同的内存地址;
而call-by-reference方式的调用参数和被调用方法中的参数,代表的是同一内存地址。
从这个意义上理解两种参数传递方式,就是很容易的了。
传值的过程:
(1)形参与实参各占一个独立的存储空间。
(2)形参的存储空间是函数被调用时才分配的。调用开始,系统为行参开辟一个临时存储区,然后将各实参之值传递给形参,这时形参就得到了实参的值。
(3)函数返回时,临时存储区也被撤销。
传值的特点:单向传递,即函数中对形参变量的操作不会影响到调用函数中的实参变量。
地址传递过程:参数是地址,实参和形参共享一个存储单元(也可以理解将实参的地址赋值给形参),对形参的操作相应的就改变了实参,此时参数传递是双向的。
利用引用类型变量进行值传递:传递是原引用变量的副本,即把原引用变量复制一份传递给方法,使得方法中的行参和实参引用的值相同,指向同一个对象的实例;引用类型变量是以对象引用的形式传递的,是将要传递的对象的引用复制给函数的形参,这时形参是实参引用的复制,注意:是引用的复制,而不是原引用,和原引用指向相同的对象,因此对于引用对象所做的更改将会直接影响原来的值,但是对于引用本身,在函数内的任何改变将不会影响原引用。
利用引用类型参数进行引用传递:传递的是引用变量的引用,此时形参相当于是实参的一个别名,两者是同一个引用。
三.ref参数与out参数
1.两者都是引用传递.
2.区别在于:ref参数在调用方法前必须几经初始化。而out参数在调用方法前可以没有初始化,他们都以引用传递方式传递。
ref
ref 关键字使参数按引用传递。其效果是,当控制权传递回调用方法时,在方法中对参数所做的任何更改都将反映在该变量中。
- 若要使用 ref 参数,则方法定义和调用方法都必须显式使用 ref 关键字。
- 传递到 ref 参数的参数必须最先初始化。这与 out 不同,out 的参数在传递之前不需要显式初始化。
- 属性不是变量,因此不能作为 ref 参数传递。
- 尽管 ref 和 out 在运行时的处理方式不同,但它们在编译时的处理方式是相同的。因此,如果一个方法采用 ref 参数,而另一个方法采用 out 参数,则无法重载这两个方法。例如,从编译的角度来看,以下代码中的两个方法是完全相同的。如果尝试这么做,将导致不能编译该代码。
- 如果一个方法采用 ref 或 out 参数,而另一个方法不采用这两类参数,则可以进行重载。
out
out 关键字会导致参数通过引用来传递。这与 ref 关键字类似。
与 ref 的不同之处:
- ref 要求变量必须在传递之前进行初始化。
- 尽管作为 out 参数传递的变量不需要在传递之前进行初始化,但需要调用方法以便在方法返回之前赋值。