【C++】C++ 引用详解 ⑦ ( 指针的引用 )

2023-08-27 20:01:43





一、二级指针可实现的效果



指针的引用 效果 等同于 二级指针 , 因此这里先介绍 二级指针 ;


使用 二级指针 作为参数 , 可以实现如下功能 :

  • 动态内存管理 : 借助二级指针 , 可以在函数中分配或释放内存 ; 如 : 创建一个动态数组或调整现有数组的大小 , 在函数中需要一个指向指针的指针作为参数 , 以便修改原始指针 ;
void createArray(int **arr, int size) {  
    *arr = malloc(size * sizeof(int));  
}
  • 修改指针的值 : 借助二级指针 , 可以在函数中修改指针的值 , 即改变它所指向的地址 ; 如果直接传递 一级指针 , 函数只能修改指针指向内存中的数据 , 指针的指向不会改变 ;
void changePointer(int **ptr) {  
    int new_value = 10;  
    *ptr = &new_value;  // 修改指针值 
}
  • 传递多维数组 : C 语言中 , 数组名本质上是指向数组第一个元素的指针 , 传递多维数组到函数中通常需要传递一个指向指针的指针 , 即二级指针 ; 借助二级指针 , 函数可以修改原始数组的行指针 ;
void process2DArray(int **array, int rows, int cols) {  
    //...  
}




二、指针的引用




1、指针的引用 等同于 二级指针 ( 重点概念 )


普通变量的 引用 , 调用时可以直接当做 普通变量 使用 , 可实现的功能 相当于 一级指针 ;

  • 普通变量 相当于 零级指针 ;

一级指针的 引用 , 调用时可以直接当做 一级指针 使用 , 可实现的功能 相当于 二级指针 ;

N 级指针的 引用 , 调用时可以直接当做 N 级指针 使用 , 可实现的功能 相当于 N + 1 级指针 ;


在 C++ 语言 中 , 使用 引用 时 , C++ 编译器 会自动将 引用 翻译为 一级指针 使用 , 自动 在 一级指针 变量 旁边加上 取地址符号 & 和 取值符号 * ;

指针的引用 就相当于 二级指针 , 其 实现的效果 , 等同于 二级指针 ;

C++ 编译器 遇到 指针的引用 时 , 会自动将 引用指针 转为 二级指针 ;



2、引用本质 - 函数间接赋值简化版本


使用函数进行间接赋值 , 需要满足如下三个条件 :

  • 函数中定义 指针类型 的 形参 , 调用函数时 修改函数外的 实参 ;
  • 将 实参 取地址 , 传递给 函数 ;
  • 在函数中 , 通过指针修改 实参的值 , 以达到修改外部变量的效果 ;

如果将 函数 的形参类型 设置为 引用 类型 , 也能达到 间接赋值 的效果 ;

引用 实际上是 把 间接赋值 的三个条件的后两个条件进行了合并 , C++ 编译器遇到引用 , 还是需要将 引用 还原为 C 语言中的 取地址 传入函数 , 在函数内部使用指针访问实参 ;


3、代码示例 - 指针的引用


该 函数 的 参数 是 一级指针的引用 , 使用该参数时 可以当做 一级指针使用 , 其效果 等同于 二级指针 ; 其效果等同于上一篇博客 【C++】C++ 引用详解 ⑥ ( 普通变量 / 一级指针 / 二级指针 做函数参数的作用 ) 中的 int getStudent(Student** stu) 函数 ;

// 参数是 一级指针的引用 
// 该参数 是 一级指针的引用 
// 使用该参数时 可以当做 一级指针使用
// 其效果 等同于 二级指针
int getStudent(Student*& p)

调用该 一级指针 的 引用 , 可以直接访问 一级指针 , 不需要使用 * 符号 ;

因此 这里 直接为 一级指针 进行内存分配 ;

如果此处是二级指针 , 需要先试用 * 符号 取出二级指针指向的一级指针 , 然后再为该 一级指针 分配内存 ;

    // 为形参中声明的 Student* 指针的引用 分配内存
    // 一维指针的引用 相当于直接访问一维指针 
    // 相当于为 main 函数中的 Student* stu 变量赋值
    p = (Student*)malloc(sizeof(Student));
    // 如果传入的是二维指针参数 Student** p
    // 上述操作等同于
    // *p = (Student*)malloc(sizeof(Student));

代码示例 :

// 导入标准 io 流头文件 其中定义了 std 命名空间
#include <iostream>
// 导入 std 命名空间
using namespace std;

struct Student
{
    char name[64];
    int age;
};

// 参数是 指针的引用 
// 该参数 是 一级指针的引用 
// 使用该参数时 可以当做 一级指针使用
// 其效果 等同于 二级指针
int getStudent(Student*& p)
{
    // 为形参中声明的 Student* 指针的引用 分配内存
    // 一维指针的引用 相当于直接访问一维指针 
    // 相当于为 main 函数中的 Student* stu 变量赋值
    p = (Student*)malloc(sizeof(Student));
    // 如果传入的是二维指针参数 Student** p
    // 上述操作等同于
    // *p = (Student*)malloc(sizeof(Student));

    if (p == NULL)
    {
        // 分配内存失败 , 返回错误码 2
        return 2;
    }

    // 设置结构体成员值
    p->age = 18;

    // 执行成功
    return 0;
}

int main() {
    // 声明 Student 对象
    Student* stu = NULL;

    // 调用函数 将二级指针传入函数 
    // 在函数内部创建 Student 对象
    getStudent(stu);

    // 打印结构体成员
    printf("stu->age = %d\n", stu->age);


    // 控制台暂停
    system("pause");

    return 0;
}

执行结果 :

stu->age = 18
请按任意键继续. . .

在这里插入图片描述

更多推荐

docker四种网络模式

文章目录一.为什么要了解docker网络二.docker网络理论三.docker的四类网络模式3.1bridge模式3.2host模式3.3container模式3.4none模式四.bridge模式下容器的通信4.1防火墙开启状态4.2防火墙关闭状态一.为什么要了解docker网络当你开始大规模使用Docker时,你

Docker基础-namespace

Docker-namespacenamespace基础命令dd命令mkfsdfmountunsharepid隔离试验mount隔离namespacenamespace是Linux内核用来隔离内核资源的方式。通过namespace可以让一些进程只能看到与自己相关的一部分资源,而另外一些进程也只能看到与它们自己相关的资源,

Spark 框架概述

目录一、Spark是什么1.1统一分析引擎?二、Spark风雨十年​三、SparkVSHadoop(MapReduce)3.1面试题:Hadoop的基于进程的计算和Spark基于线程方式优缺点?四、Spark四大特点​4.1速度快4.2易于使用4.3通用性强​4.4运行方式五、Spark框架模块5.1介绍5.2Spar

Python+Selenium定位不到元素常见原因及解决办法(报:NoSuchElementException)

这篇文章主要介绍了Python+Selenium定位不到元素常见原因及解决办法(报:NoSuchElementException),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧在做web应用的自动化测试时,定位元素是必不可少的,这个过程经常会碰到定

虹科分享 | 软件供应链攻击如何工作?如何评估软件供应链安全?

说到应用程序和软件,关键词是“更多”。在数字经济需求的推动下,从简化业务运营到创造创新的新收入机会,企业越来越依赖应用程序。云本地应用程序开发更是火上浇油。然而,情况是双向的:这些应用程序通常更复杂,使用的开放源代码比以往任何时候都包含更多的漏洞。此外,威胁行为者正在创造和使用更多的攻击方法和技术,通常是组合在一起的。

华为云云耀云服务器L实例评测|部署功能强大的监控和可视化工具Grafana

应用场景Grafana介绍Grafana是一个功能强大的监控和可视化工具,适用于各种行业和应用场景,如IT运维监控、网络监控、能源管理、金融市场分析等。它提供了灵活的数据源支持、强大的可视化功能和告警机制,以及注释和过滤功能,使得用户能够更好地理解和分析实时数据。下面的监控查询面板都是使用Grafana制作的。一个用于

Rust的注释与文档

rust中//!和///有什么区别?在Rust中,//!和///是特殊注释语法,用于文档注释(DocumentationComments)。它们用于编写文档,并生成Rust代码的API文档。//!用于编写模块级别的文档注释,通常放置在模块的开头。它允许您编写与整个模块相关的文档。这些注释会被Rust编译器解析,生成与模

zookeeper集群

一,zookeeper定义Zookeeper是一个开源的分布式的,为分布式框架提供协调服务的Apache项目。二,zookeeper工作机制Zookeeper从设计模式角度来理解:是一个基于观察者模式设计的分布式服务管理框架,它负责存储和管理大家都关心的数据,然后接受观察者的注册,一旦这些数据的状态发生变化,Zooke

论文笔记 DETR

detr摘要和引言2020论文facebook不需要proposal,不需要基于anchor的先验知识(比如预训练的模型),也不需要NMS进行筛选,直接端到端不需要后处理利用transformer的全局建模能力,看成集合预测问题,不会输出很多冗余的框,直接端到端,不需要NMS,简化了训练和部署NMS:非极大值抑制,抑制

Web3.0时代什么时候到来,Web3.0有什么机会?

🏆作者简介,黑夜开发者,CSDN领军人物,全栈领域优质创作者✌,CSDN博客专家,阿里云社区专家博主,2023年6月CSDN上海赛道top4。🏆数年电商行业从业经验,历任核心研发工程师,项目技术负责人。🎉欢迎👍点赞✍评论⭐收藏文章目录🚀一、前言🚀二、Web1.0-Web3.0🔎2.1Web1.0:信息的获

穿越时空的创新:解析云原生与Web3.0的奇妙渊源

🌷🍁博主猫头虎带您GotoNewWorld.✨🍁🦄博客首页——猫头虎的博客🎐🐳《面试题大全专栏》文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺🌊《IDEA开发秘籍专栏》学会IDEA常用操作,工作效率翻倍~💐🌊《100天精通Golang(基础入门篇)》学会Golang语言,畅玩云原生,走遍大

热文推荐