C++中函数调用时的三种参数传递方式
在C++中,参数传递的方式是“实虚结合”。
- 按值传递(pass by value)
- 地址传递(pass by pointer)
- 引用传递(pass by reference)
按值传递的过程为:首先计算出实参表达式的值,接着给对应的形参变量分配一个存储空间,该空间的大小等于该形参类型的,然后把实参表达式的值一一存入到形参变量分配的存储空间中,成为形参变量的初值,供被调用函数执行时使用。这种传递是把实参表达式的值传送给对应的形参变量,故称这种传递方式为“按值传递”。
使用这种方式,调用函数本身不对实参进行操作,也就是说,即使形参的值在函数中发生了变化,实参的值也完全不会受到影响,仍为调用前的值。
1 /* 2 pass By value 3 */ 4 #include <iostream> 5 using namespace std; 6 void swap(int,int); 7 int main() 8 { 9 int a = 3, b = 4; 10 cout << "a = " << a << ", b = " 11 << b << endl; 12 swap(a,b); 13 cout << "a = " << a << ", b = " 14 << b << endl; 15 return 0; 16 } 17 void swap(int x, int y) 18 { 19 int t = x; 20 x = y; 21 y = t; 22 }
如果在函数定义时将形参定义为指针,对这样的函数进行调用时就需要指定地址值形式的实参。这时的参数传递方式就是地址传递方式。
地址传递与按值传递的不同在于,它把实参的存储地址传送给对应的形参,从而使得形参指针和实参指针指向同一个地址。因此,被调用函数中对形参指针所指向的地址中内容的任何改变都会影响到实参。
1 /* 2 pass by reference 3 */ 4 #include <iostream> 5 using namespace std; 6 void swap(int*,int*); 7 int main() 8 { 9 int a = 3, b = 4; 10 cout << "a = " << a << ", b = " 11 << b << endl; 12 swap(&a,&b); 13 cout << "a = " << a << ", b = " 14 << b << endl; 15 system("pause"); 16 return 0; 17 } 18 void swap(int *x,int *y) 19 { 20 int t = *x; 21 *x = *y; 22 *y = t; 23 }
按值传递方式容易理解,但形参值的改变不能对实参产生影响。
地址传递方式虽然可以使得形参的改变对相应的实参有效,但如果在函数中反复利用指针进行间接访问,会使程序容易产生错误且难以阅读。
如果以引用为参数,则既可以使得对形参的任何操作都能改变相应的数据,又使得函数调用显得方便、自然。引用传递方式是在函数定义时在形参前面加上引用运算符“&”。
1 /* 2 pass by reference 3 */ 4 #include <iostream> 5 using namespace std; 6 void swap(int&,int&); 7 int main() 8 { 9 int a = 3, b = 4; 10 cout << "a = " << a << ", b = " 11 << b << endl; 12 swap(a,b); 13 cout << "a = " << a << ", b = " 14 << b << endl; 15 system("pause"); 16 return 0; 17 } 18 void swap(int &x,int &y) 19 { 20 int t = x; 21 x = y; 22 y = t; 23 }
比较:
对比参数的三种传递方式,可以发现“引用传递”和“指针传递”的性质一样,而书写方式像“值传递”。引用传递可以做的任何事指针也能够做到,因为指针能够毫无约束地操作内存中的东西,这种强大的功能背后也必将隐藏着巨大的危险,所以慎用指针。