我们需要传数据而不改变数据存储,直接传值,如int a;
我们需要传数据,并且改变值大小,需要传地址,如 int * pa;
我们需要传数据,并改变数结构中指针的指向,需要传二级指针,如链表中的 node * * l;
...
这是c语言中传值的形式。参考我之前的一篇文章https://blog.csdn.net/weixin_41143631/article/details/82717506
以前是passl-by-value,而c++在c11中,引入了pass-by-reference,也就是传引用。c++需要一个标识符&。
给出下面代码
void my_swap(int* x, int* y)
{
*x = *x^*y;
*y = *x^*y;
*x = *x^*y;
cout << "函数中参数x的地址 " << &x << endl;
}
void my_swap(int&a, int&b)
{
a = a^b;
b = a^b;
a = a^b;
cout <<"函数中参数a的地址 "<< &a<< endl;
}
int main()
{
int www = 1;
int a = 0; int b = 100;
int x = 0; int y = 100;
my_swap(&x, &y);
my_swap(a, b);
cout << a << " 主函数 a 的地址 "<<&a<<endl;
cout << x << " 主函数x的地址 " <<&x<< endl;
}
前者swap是传值(生成拷贝,传地址),而后者直接是传引用,形参和实参的本质是一样,引用只是一个别名。
运行结果如下
可以明显看到,这2个重载函数中使用传指针,所指向的地址是不同的,而使用传引用,所指向的地址是相同的。
传引用:被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。
传值:被调函数的形式参数作为被调函数的局部变量处理,即在栈中开辟了内存空间以存放由主调函数放进来的实参的值,从而成为了实参的一个副本。
int a=0; //定义a是一个int类变量
int& ra=a; //声明ra是a的“引用”,变量ra具有变量a的地址
//引用不能在引用的基础上再引用。
顺便说一下,gcc在编译时,O2级别优化,传引用,和传地址的汇编代码是一样的。
在微软的vc编译器(vs2013)运行时,直接优化,传引用,和传地址的汇编代码是一样的。
所以在我们写代码时,传引用,传指针都可以,不过我自己也趋向于写引用,在c++的模板中也大量使用引用,从制度上完善代码规范,能防微杜渐。
下面说一下,传引用,和我们常说的“传指针”之间的一些小区别。
A,传引用需要初始化,指针不需要(但指针推荐每次都初始化,即使无值,也初始化为NULL)。
B,使用sizeof对其求大小不一样,引用是对应数据的实际大小,而指针则依据机器固定为相应大小(32位为4字节)。
C,指针更加灵活,++,--可以来访问,而引用没有这些。有多级指针,没有多级引用。
D,引用相当于和被引用者“绑定”,而指针可以不断改变。
...
从安全的角度,引用能替代指针,这个在很多高级语言,不论是解释性语言还是编译语言中都得到了体现。
但维持c++的灵活,我们依然可以使用指针,不过推荐使用引用。