C++参数传递
目录
1.基本参数传递方式
按值传递
将实参复制一份给形参,形参为函数的局部变量,因此函数对形参操作对实参没有影响。若传递对象会产生对象副本,会调用拷贝构造函数,操作完后要调用析构函数。
指针传递
形参为指向实参地址的指针,其也算一种按值传递,只不过是将实参的地址作为参数传递给形参,因此函数对形参的指向操作时会改变实参。若传递对象会产生对象副本,会调用拷贝构造函数,操作完后要调用析构函数。
引用传递
形参相当于实参的别名,因此函数相当于直接对实参进行操作。若传递对象不产生对象副本,效率更高。
下面看看三种参数传递的具体代码:
#include <iostream>;
using namespace std;
void swap1(int a, int b); //按值传递
void swap2(int *a, int *b); //指针传递
void swap3(int &a, int &b); //引用传递
int main()
{
int a = 5, b = 3;
cout << "原始数据:" << endl;
cout << "a=" << a << ",b=" << b << endl;
swap1(a, b);
cout << "按值传递交换:" << endl;
cout << "a=" << a << ",b=" << b << endl;
swap2(&a, &b);
cout << "指针传递交换:" << endl;
cout << "a=" << a << ",b=" << b << endl;
swap3(a, b);
cout << "引用传递交换:" << endl;
cout << "a=" << a << ",b=" << b << endl;
return 0;
}
//按值传递
void swap1(int a, int b)
{
int tmp = a;
a = b;
b = tmp;
}
//指针传递
void swap2(int *a, int *b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
//引用传递
void swap3(int &a, int &b)
{
int tmp = a;
a = b;
b = tmp;
}
运行结果:
总结
- 可以看到按值传递不能起到交换的作用,形参改变后会被释放而不会影响实参。
- 而指针传递虽然是将实参的地址进行按值传递,函数结束后地址会被释放,但地址内的值已经改变,也就是实参已经改变。
- 引用传递的参数只是实参的一个别名,因此所有对形参的操作都等同于在实参上操作。
- 应用范围:若只需得到实参的计算结果而不需要对实参进行改变则使用按值传递;若需要对实参的值改变则使用指针和引用,由于引用不会运行构造函数,效率更高,因此程序中推荐使用引用。
2.指针与引用区别
指针 | 引用 |
---|---|
定义:int *p; | 定义:int &b=a; |
初始化:p=&a; 或int *p=&a; | 必须定义同时初始化 |
可修改指向,指向可为空 | 初始化后不可改变,指向必须有效 |
指针是个实体,有多级指针 | 引用是个别名,没有地址,没有多级引用 |
不进行安全检查 | 引用过程会进行安全检查 |
sizeof(指针)得到指针大小 | sizeof(引用)得到变量的大小 |
自增自减操作是对地址的操作 | 自增自减操作是对所指变量操作 |
3.参数为指针的指针或指针的引用
若参数为指针,并且需要对指针本身进行修改,那么就需要将函数参数类型设为指针的指针或者指针的引用,如下面例子:
#include <iostream>;
#include <string>;
using namespace std;
void func(char *a); //指针
void func1(char **a); //指针的指针
void func2(char *&a); //指针引用
int main()
{
string str= "ab#cde";
//b,c,d为指向字符串首位的地址
char *b = &str[0];
char *c = &str[0];
char *d = &str[0];
cout << "b=" << b << endl << "指针:" ;
func(b);
cout << endl << endl;
cout << "c=" << c << endl << "指针的指针:";
func1(&c);
cout << endl << endl;
cout << "d=" << d << endl << "指针引用:";
func2(d);
cout << endl << endl;
return 0;
}
//指针
void func(char *a)
{
if (*a == '#')
{
a++;
return;
}
if (*a == '\0')
return;
else
{
cout << *a << ' ';
a++;
}
func(a);
func(a);
}
//指针的指针
void func1(char **a)
{
if (**a == '#')
{
(*a)++;
return;
}
if (**a == '\0')
return;
else
{
cout << **a << ' ';
(*a)++;
}
func1(a);
func1(a);
}
//指针引用
void func2(char *&a)
{
if (*a == '#')
{
a++;
return;
}
if (*a == '\0')
return;
else
{
cout << *a << ' ';
a++;
}
func2(a);
func2(a);
}
运行结果为:
我们分析一下这段程序。这段程序的作用是打印出字符串中的每个字符,若遇到#号则跳过。b、c、d为指向字符串首位的地址,分别将这三个指针作为参数传递给三个递归函数func()、func1()、func2()。接下来我们逐个分析各个函数:
(1)void func(char *a);
直接把指针b作为参数传递给func()函数,由于每次遇到return都会释放指针a,因此指针的指向并不会改变。运行过程如下,输出为:a b b。
(2)void func1(char **a);
func1()函数把指针的指针作为参数,*a代表指针,a代表指针的指针,每当遇到return时指针的指针a都会被释放,但指针的指向已经改变,因此在遇到字符’#'后指针已经指向后面的字符,可以继续输出后面的字符。运行过程如下,输出为:a b c d e。
(3)void func2(char *&a);
func2()函数把指针的引用作为参数,因此指针会一直自增,不会随着return而释放,直至指针指向’\0’,程序停止。
总结
若实参为指针,并且想要对指针本身进行修改,那么就需要使用指针的指针或者指针引用作为函数参数。