zoukankan      html  css  js  c++  java
  • 由 *& 引发的对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. 引用是类型安全的,而指针不是。引用比指针多了类型的检查。
  • 相关阅读:
    STM32CubeMX 使用
    Zookeeper集群搭建
    golang zookeeper监听事件报错
    git push 报错
    springboot使用postgresql模式下数据库表找不到
    不要在循环中访问数据库,这样会严重影响数据库性能
    SQL查询效率(Oracle)
    游标 数据集 效率比较
    oracle 视图
    INDEX SKIP SCAN 和 INDEX RANGE SCAN以及索引会失效
  • 原文地址:https://www.cnblogs.com/chunzhulovefeiyue/p/8525843.html
Copyright © 2011-2022 走看看