C/C++语言中函数参数的传递有:值传递,地址传递,引用传递这三种形式.
所有的函数都使用在程序运行栈(run-time stack) 中分配的存储区该存储区一直保持与该函数相关联直到函数结束为止那时存储区将自动释放以便重新使用该函数的整个存储区被称为活动记录(activation record).
系统在函数的活动记录中为函数的每个参数都提供了存储区参数的存储长度由它的型来决定参数传递是指用函数调用的实参值来初始化函数参数存储区的过程.
#include <stdio.h>
swap1(int a,int b)//按值传递
{
int temp;
temp=a;
a=b;
b=temp;
}
swap2(int *a,int* b)//按指针传递
{
int temp;
temp=*a;
*a=*b;
*b=temp;
}
swap3(int &a,int& b)//按引用传递
{
int temp;
temp=a;
a=b;
b=temp;
}
void main()
{
int i1=30,i2=40;
swap1(i1,i2);
printf("a=%d,b=%d\n",i1,i2);
int a2=3,b2=4;
swap2(&a2,&b2);
printf("a=%d,b=%d\n",a2,b2);
int a3=22,b3=33;
swap3(a3,b3);
printf("a=%d,b=%d\n",a3,b3);
}
输出:
按值传递:参数传递的缺省初始化方法是把实参的值拷贝到参数的存储区中这被称为按值传递(pass-by-value).按值传递时函数不会访问当前调用的实参,函数处理的值是它本地的拷贝这些拷贝被存储在运行栈中,因此改变这些值不会影响实参的值,一旦函数结束了函数的活动记录 .将从栈中弹出,这些局部值也就消失了
在按值传递的情况下实参的内容没有被改变这意味着程序员在函数调用时无需保存和恢复实参的值.
但是按值传递并不是在所有的情况下都适合,不适合的情况包括:
1:当大型的类对象必须作为参数传递时对实际的应用程序而言分配对象并拷贝到栈中的时间和空间开销往往过大.
2:当实参的值必须被修改时,例如在函数swap()中用户想改变实参的值但是在按值传递的情况下无法做到.
// swap() 没有交换两个实参的值,仅仅是交换了形参v1,v2的值!
void swap( int v1, int v2 ) {
int tmp = v2;
v2 = v1;
v1 = tmp;
}
swap()交换实参的本地拷贝代表swap()实参的变量并没有被改变
为了获得期望的行为程序员可以使用两种方法:
一种方法是参数被声明成指针,例如swap()可重写如下
// pswap()交换v1和v2指向的值
void pswap( int *v1, int *v2 ) {
int tmp = *v2;
*v2 = *v1;
*v1 = tmp;
}
我们必须修改main()来调用pswap() 现在程序员必须传递两个对象的地址而不是对象本身
pswap( &i, &j );
修改后的程序编译运行后的结果显示了它的正确性
// 使用指针使程序员能够访问当前调用的实参
Before swap(): i: 10 j: 20
After swap(): i: 20 j: 10
第二种方法是把参数声明成引用,例如swap()可重写如下
// rswap() 交换v1和v2引用的值
void rswap( int &v1, int &v2 ) {
int tmp = v2;
v2 = v1;
v1 = tmp;
}
main()中rswap()的调用看起来像原来的swap()调用
rswap( i, j );
引用参数:把参数声明成引用,实际上改变了缺省的按值传递参数的传递机制,在按值传递时函数操纵的是实参的本地拷贝,当参数是引用时函数接收的是实参的左值而不是值的拷贝,这意味着函数知道实参在内存中的位置,因而能够改变它的值或取它的地址.
什么时候将一个参数指定为引用比较合适呢?
1:像swap()的情况,它必须将一个参数改变成指针来允许改变实参的值时就比较合适.
2:引用参数的第二种普遍用法是向主调函数返回额外的结果,
3:第三种用法是向函数传递大型类对象.