由 *& 引发的对C++中值传递、指针传递、引用传递的探讨

由 &* 引发的对C++中值传递、指针传递、引用传递的探讨

问题出于今天在写Leetcode时,在Discuss中发现的 &* 写法,于是找了一些相关资料,并且整理如下。

首先,说一下C++ 中*a 和 *&a作为函数的参数时的区别

在之前写代码中,我们当遇到形如

void foo(int *ptr);

这样的函数声明时,函数的形参是一个指针,它实际上是值传递, 如果不清楚请继续往下看,比如,我们这样调用

int a = 3;
int *pValue = &a;
foo(pValue);

这种情况下,pValue的值是不会被foo函数改变的,也就是说pValue肯定是指向a的。例如我们在foo()函数中进行下面的操作

void foo(int *ptr)
{
    ptr = nullptr;
}

在foo(pValue)调用后,pValue仍然为a的地址, *pValue仍然为3。

如果我们更改一下声明

void foo(int*& ptr)
{
    ptr = nullptr;
}

在foo(pValue)调用后,pValue成为了一个空指针。

为什么呢?

要从值传递、指针传递、引用传递这几个方面开始看。

值传递

形参为指向实参的拷贝,改变形参的值不会影响外部实参的值。从被调用函数的角度来说,值传递是单向的(实参->形参), 参数的值只能传入,不能传出。当函数内部需要修改参数,并且不希望这个改变影响调用者时,采用值传递。

指针传递

指针,实际上是地址的一个拷贝,其实也是值传递。你不能改变原来变量的值,但你能改变这个地址指向的内容。

沿着上面的foo(int *ptr)来说,你可以通过*ptr = 5来改变pValue指向(即a)的值,但是不能通过函数内ptr=nullptrpValue为空指针。

引用传递

形参相当于实参的“别名”,对形参的操作其实就是对实参的操作,在引用传递过程中,被调用函数的形参虽然也作为局部变量在栈中开辟内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量。

为了进一步加深对指针和引用的区别,下面从编译器的角度来阐释它们之间的区别。

程序在编译时分别将指针引用添加到符号表上,符号表上记录的是变量名和变量所对应的地址。指针变量在符号表上对应的地址值为指针变量的地址值;引用在符号表上对应的地址值为引用对象的地址值。符号表生成后就不会再改,因此指针可以改变其指向的对象(指针变量中值可以改),而引用对象则不能更改。

最后,总结一下指针和引用的相同点和不同点

  • 相同点
    1. 指针指向一块内存,它的内容是所指内存的地址;而引用则是某块内存的别名
  • 不同点
    1. 指针是一个实体,而引用是一个别名
    2. 引用只能在定义是被初始化一次,之后不可变;指针可变。引用“从一而终”, 指针可以“见异思迁”
    3. 引用没有const, 指针有const,具体内容见这里
    4. 引用不能为空,指针可以为空
    5. sizeof(引用)得到的是所指向的对象的大小, 而sizeof(指针)得到的是指针本身的大小
    6. 指针和引用的自增运算含义不同
    7. 引用是类型安全的,而指针不是。引用比指针多了类型的检查。
posted @ 2018-03-07 22:34  一棵球和一枝猪  阅读(331)  评论(0编辑  收藏