在最近的学习中,经常为传参而感到困惑,因为自己并不能明确地知道彼此之间的区别,为了几觉自己的疑惑,还有可能与我有相同疑惑的朋友的问题,让我们在这里进行一番讨论,并进行总结:
C++中支持三种参数传递方式:
1).按值传递(pass by value) value
2).地址传递(pass by pointer) *value
3).引用传递(pass by reference) &value
值传递:
首先计算出实参表达式的值,接着给对应的形参变量分配一个存储空间,该空间的大小等于该形参类型的,然后把以求出的实参表达式的值一一存入到形参变量分配的存储空间中,成为形参变量的初值,供被调用函数执行时使用。这种传递是把实参表达式的值传送给对应的形参变量,故称这种传递方式为“按值传递”
并且在传递大量数据是,比如数组,在时间空间上的开销较大
一个例子给大家:
void Swap(int a,int b)
{
a ^= b;
b ^= a;
a ^= b;
}
int main()
{
int a = 5;
int b = 6;
cout << a << " " << b<< endl;
Swap(a,b);
cout << a << " " << b<< endl;
return 0;
}
大家会发现,使用这种方式,调用函数本省不对实参进行操作,也就是说,即使形参的值在函数中发生了变化,实参的值也完全不会受到影响,仍为调用前的值。
前后两次打印的内容一样,可是调用了Swap函数了,这是为什么呢?
因为在函数里,改变的形参里值,并没有改变实参地址里面的内容,所以在函数调用完成后,栈帧结构销毁,a还是原来的啊,b还是原来的不;这就是传值的弊端,不能改变原来的内容,如果只是为了得到最大值、最小值的话,传值并没有错误,但是要改变内存单元里的内容时,传值并不能满足你的需求,所以在C语言中还有另一种传参方式–>传址,自然C++也适用。
地址传递:
地址传递与按值传递的不同在于,它把实参的存储地址传送给对应的形参,从而使得形参指针和实参指针指向同一个地址。因此,被调用函数中对形参指针所指向的地址中内容的任何改变都会影响到实参。
void Swap(int *a,int *b)
{
*a ^= *b;
*b ^= *a;
*a ^= *b;
}
int main()
{
int a = 5;
int b = 6;
cout << a << " " << b<< endl;
Swap(&a,&b);
cout << a << " " << b<< endl;
return 0;
}
按值传递方式容易理解,但形参值的改变不能对实参产生影响。
地址传递方式虽然可以使得形参的改变对相应的实参有效,但如果在函数中反复利用指针进行间接访问,会使程序容易产生错误且难以阅读。
在C++中又提出了传引用
引用传递
如果以引用为参数,则既可以使得对形参的任何操作都能改变相应的数据,又使得函数调用显得方便、自然。引用传递方式是在函数定义时在形参前面加上引用运算符“&”。
void Swap(int &a,int &b)
{
a ^= b;
b ^= a;
a ^= b;
}
int main()
{
int a = 5;
int b = 6;
cout << a << " " << b<< endl;
Swap(a,b);
cout << a << " " << b<< endl;
return 0;
}
传引用,在中间产生的临时对象会记住所有动作,就算函数的栈帧结构全部销毁,并不会影响到引用参数的临时对象,这与引用的底层实现有关,可以阅读下面这篇文章,希望有所帮助
:C++中“引用”的底层实现