深度分析c+引用的本质以及引用与指针的区别

文章目录

  • 引用的概念
  • 引用的定义
  • 引用的特性
  • 引用的权限问题
  • 引用的使用方式
  • 引用作参数
  • 引用作返回值
  • 指针的本质
  • 引用和指针的区别

引用的概念

引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。简单理解为:在语法层面上,引用就是给变量重新取一个名字

引用的定义

引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟另外的内存空间进行存储,它与引用的变量共用的是同一块内存空间的地址。

格式如下:
类型& 引用变量名(对象名) = 引用实体;
而此处的&不是取地址操作符,而是起标志作用,标志所定义的标识符是个引用.

int main() {int a = 1;int& b = a; //此处就是引用的定义return 0;
}

此处就相当于变量a,b共用同一块内存地址空间
在这里插入图片描述

引用的特性

  1. 引用在定义时必须初始化
  2. 不能有空引用
  3. 一个变量可以有多个引用(相当于有多个别名)
  4. 引用一旦引用一个实体,不能引用其他实体
  5. 没有多级引用,再不能引用其他实体

如图
在这里插入图片描述

引用的权限问题

先看图代码
在这里插入图片描述

为什么图中不加const会发生报错呢???这就不得不提到引用的权限问题
接下来我们来分析一下

int main()
{const int a = 1;//变量a被const修饰,a的值不能改,权限是只读int&d = a;//d是a的别名,但d的改变会改变a,也就变成了可读可写,扩大了权限const int& d = a;//d被const修饰,所以d也只可读,权限与a相同,不存在扩大权限return 0;
}

所以之所以不加const会报错,就是因为权限被放大了

再看这个代码
在这里插入图片描述
这个代码能够顺利通过,为什么?

int main()
{int a = 1;//权限是可读可写const int& b = a;//b被const修饰,权限为可读,但不可写return 0;
}

通过这段代码我们可以得出,权限是可以被缩小的
注意:这段代码如果你想修改a的值,可以通过a来进行修改,但不能通过b,并且修改了之后,b的值仍然会跟随着a进行改变
如图:
在这里插入图片描述

接下来我们再看看一个特殊的例子

在这里插入图片描述
如果没有const这一行代码,可能大家会认为是a的类型(int)和b的类型(double)不匹配而导致的错误,但事实并非如此.当你加了const之后,便不会有报错,这是为什么呢?
这其中就要提到C语言中的类型转换(包括隐式类型转换和显式类型转换)
如下面这个例子
在这里插入图片描述
又比如:
在这里插入图片描述
总结:类型转换的时候都会产生一个临时变量,而这个临时变量是会被const修饰的,具有常性

所以现在我们知道了,上图那个例子报错就是因为权限被放大了,所以我们应该加上const

最后需要补充的是:权限问题只针对于引用和指针

引用的使用方式

1.引用普通变量(最常见的)

int main()
{int a = 10; //a是一个普通整型变量int & b = a;return 0;
}

2.常引用

int main()
{const int a = 1;const int& c = a;//保持权限相等const int& z =10;//常数只可读,所以要用const限制成只读return 0;
}

3.指针引用

int main()
{int a = 100;int* p = &a;int*& k = p;//这是个指针引用,k就是个指针p的别名return 0;}

引用作参数

在使用带参函数的时候,由于一般函数的参数是实参的拷贝,但有些函数的操作可能是要对原变量进行改变的,C语言常用的做法是指针来传递原变量地址,这样的好处是如果需要将改变传回或者改变原变量则不需要返回值,可以通过传入指针直接改变。而C++提供了引用的新特性,可以使用引用传参
比如对于交换两数:

void swap(int *a, int *b)  //c语言的老方法
{int tmp = *a;*a = *b;*b = tmp;
}
void swap(int &a, int &b) //c++新引入的特性-引用
{int tmp = a;a = b;b = tmp;
}

其实在c++中分两种情况看待
①如果变量是内置类型,如char,int等,那么推荐值传递
因为编译器将直接使用寄存器进行操作,显然这是最快的,如果要用指针和引用,那么会多一次放存操作
②如果变量是对象,那么使用引用将是首选,并且参数里面的引用最好加上const
当需要传递的值很大,寄存器不够用时,那么使用指针或者引用,将只需要传递变量的地址就可以了

引用作返回值

说到传引用返回又不得不提到传值返回,那接下来我们对两者进行分析
1.对于传值返回,一般返回值都会建立一个临时变量,产生一个拷贝副本,而大多数情况下这个临时拷贝也是通过寄存器返回.
在这里插入图片描述
2.而传引用返回,不会产生值的副本,而是将其返回值直接传递给这个return后面的值(原因是因为本身是传引用返回,传的变量的别名,可以想成这个函数的最终效果就是一个变量),所以传引用返回可以直接当左值使用

//函数fun
int& fun()
{//...
}
//main函数
int main()
{fun()++; //当左值使用,直接进行++return 0;
}

指针的本质

在开始讲引用的概念时,我们强调了,在语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间.但其实语法概念只是帮助我们更加方便的使用引用.
底层实现上实际是有空间的,引用的内部实现机制其实就是指针

通过下图底层汇编代码的角度也能够看到,指针和引用在底层汇编角度一模一样

在这里插入图片描述

指针和引用其实是一样的,但我们还能单独使用引用,原因就是编译器帮我们做了很多工作

就以上面代码为例:
int & ra = a;,编译器会自动转化成 int * const ra= a;(注意这是指针常数,这也解释了引用特性中的第4条为什么不能更改)
a = 20;,编译器会自动转化成 *a = 20;


下面这段引用的代码我们用底层指针进行分析

void func(int& ref)
//编译器发现参数为引用,便会转化成int* const ref = &a 
{ref = 100; //ref为引用,编译器转化为*ref = 100
}
int main()
{int a = 10;int& ref = a;ref = 20;//内部发现ref是引用,故编译器转为*ref = 20func(a);return 0;
}

总结:虽然引用的本质是指针但更为准确来说是加了const修饰的指针,也就是指针常量! ! !

引用和指针的区别

所以正是因为引用本质是指针,但又并非普通指针,所以引用和指针也就有了一些区别

  1. 引用语法概念上定义一个变量的别名,指针存储一个变量地址。
  2. 引用在定义时必须初始化,指针没有要求
  3. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体
  4. 没有NULL引用,但有NULL指针
  5. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节)
  6. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
  7. 有多级指针,但是没有多级引用
  8. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
  9. 引用比指针使用起来相对更安全(只能说是相对安全)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/107831.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言——二周目——数据在内存中的存储

目录 一、整数的存储方式 二、浮点数的存储方式 一、整数的存储方式 因为CPU只有加法器,所以对于整型来说,数据在内存中通常采用补码的方式进行储存。 在这里复习一下原码、反码、补码。 正数和无符号数的原码、反码、补码相同; 负数的原…

depcheck检查项目依赖的安装情况-帮你解决各种项目运行灵异事件

depcheck检查项目缺失的依赖 depcheck介绍与安装介绍安装 depcheck使用基础使用注意 进阶使用 删除多余的依赖注意 depcheck介绍与安装 介绍 工作中,以下的场景恐怕大家都有经历过: 从代码仓库上面 clone 的项目,自己本地一运行就报错… 用…

网工实验笔记:MQC原理与配置

一、概述 MQC(Modular QoS Command-Line Interface,模块化QoS命令行)是指通过将具有某类共同特征的数据流划分为一类,并为同一类数据流提供相同的服务,也可以对不同类的数据流提供不同的服务。 MQC三要素 流分类&am…

流量代理——正向代理

流量代理 正向代理和反向代理 正向代理就是客户端和其他所有服务器(重点:所有)的代理者。 反向代理是客户端和所要代理的服务器之间的代理。 流量转发工具 需要放在拿到shell的服务器上可使用 lcx:端口流量转发,不具…

Motorola IPMC761 使用边缘TPU加速神经网络

Motorola IPMC761 使用边缘TPU加速神经网络 人工智能(AI)和机器学习(ML)正在塑造和推进复杂的自动化技术解决方案。将这些功能集成到硬件中,解决方案可以识别图像中的对象,分析和检测模式中的异常或找到关键短语。这些功能对于包括但不限于自动驾驶汽车…

Elasticsearch系列组件:Logstash强大的日志管理和数据分析工具

Elasticsearch 是一个开源的、基于 Lucene 的分布式搜索和分析引擎,设计用于云计算环境中,能够实现实时的、可扩展的搜索、分析和探索全文和结构化数据。它具有高度的可扩展性,可以在短时间内搜索和分析大量数据。 Elasticsearch 不仅仅是一个…

JavaScript反爬虫技巧详细攻略

在互联网时代,网站采取了各种手段来防止被爬虫抓取数据,其中最常见的就是JavaScript反爬虫技巧。本文将揭示一些常用的JavaScript反爬虫技巧,并提供一些实际操作建议,帮助您保护自己的爬虫免受检测和封禁。 1、为什么网站使用Java…

python 机器视觉 车牌识别 - opencv 深度学习 机器学习 计算机竞赛

1 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 基于python 机器视觉 的车牌识别系统 🥇学长这里给一个题目综合评分(每项满分5分) 难度系数:3分工作量:3分创新点:3分 🧿 更多资…

yolo配置(windows)

文章目录 一、下载Anaconda和pycharm1 、Anaconda官方下载地址:1.2 Anaconda 的安装 下载好之后双击打开可执行安装文件:1.3 进入到安装界面:1.4 这里建议两个都勾选(第一个选项是将 Anaconda 添加到环境变量中,不勾选…

2023_Spark_实验十七:导入招聘大数据(项目)

一、爬虫爬取的招聘网站数据 二、在MySQL中创建空表 SET FOREIGN_KEY_CHECKS0;-- ---------------------------- -- Table structure for jd_jobs -- ---------------------------- DROP TABLE IF EXISTS jd_jobs; CREATE TABLE jd_jobs (job_name text,job_date text,minSale…

游戏缺少dll文件用什么修复?dll多种修复方法指南

在玩游戏时,有时候可能会遇到游戏缺少dll文件的问题。dll文件是动态链接库的缩写,它包含了一些函数和资源,游戏运行需要依赖这些文件。如果缺少了某个dll文件,游戏就可能无法正常运行。那么游戏缺少dll文件用什么修复?…

Win10 搭建FTP服务器

1. FTP 服务器用途 局域网中,资料共享,如果想实现外网访问可以设置路由端口映射(不建议外网一旦打开风险增大) 2. FTP服务器可以设置用户权限有什么? 用户只能读取 用户只能写入 用户读取写入 使用场景&#xff…

html进阶语法

html进阶 列表、表格、表单 目标:掌握嵌套关系标签的写法,使用列表标签布局网页 01-列表 作用:布局内容排列整齐的区域。 列表分类:无序列表、有序列表、定义列表。 无序列表 作用:布局排列整齐的不需要规定顺序的…

BAT027:删除当前目录指定文件夹以外的文件夹

引言:编写批处理程序,实现删除当前目录指定文件夹以外的文件夹。 一、新建Windows批处理文件 参考博客: CSDNhttps://mp.csdn.net/mp_blog/creation/editor/132137544 二、写入批处理代码 1.右键新建的批处理文件,点击【编辑】…

docker入门加实战—网络

docker入门加实战—网络 我们运行了一些容器,但是这些容器是否能够进行连通呢?那我们就来试一下。 我们查看一下MySQL容器的详细信息: 主要关注,Networks.bridge.IPAddress属性信息: docker inspect mysql # 或者过…

for循环遍历的`form表单组件`rules规则校验失效问题——下拉框选择之后还是报红---亲测有效

问题: 大概的效果就是这种, for循环选择之后还是还是报红 看文章之前 : 先检查 model rules pops 有没有判定好 解决: 参考了他的 for循环遍历的form表单组件rules规则校验失效问题——输入内容后依然提示必填,亲测有效——基础积累_a-form-model的validat…

互联网Java工程师面试题·Java 总结篇·第四弹

目录 31、String s new String(“xyz”);创建了几个字符串对象? 32、接口是否可继承(extends)接口?抽象类是否可实现(implements)接口?抽象类是否可继承具体类(concrete class&am…

基于IPSec VPN隧道技术的国密加密网关保障电力工控数据安全

IPSec VPN(Internet Protocol Security Virtual Private Network)隧道技术为电力工控系统提供了重要的数据安全传输手段。该技术能实现身份鉴别和数据加密传输,为系统的防护工作增添了有力的支持。 电力工控系统对数据传输的可靠性要求较高。…

SAP ERP系统解决光伏电池产业管理难题

无锡哲讯聚焦光伏行业的业务需求和流程,推出SAP光伏能源行业整体化解决方案。该系统着眼于“企业管理信息化、资源合理配置、利润扩张”三个方面,提供实用丰富的管理功能,同时具有较高的信息综合利用效率。SAP解决方案实现了光伏企业产、供、…

CEC2013(MATLAB):​白鲸优化算法(Beluga whale optimization,BWO)​求解CEC2013

一、白鲸优化算法(Beluga whale optimization,BWO) 白鲸优化算法(Beluga whale optimization,BWO)由Changting Zhong等人于2022年提出,该算法模拟了白鲸游泳,觅食和“鲸鱼坠落”行为…