【C++干货基地】C++引用与指针的区别:深入理解两者特性及选择正确应用场景


在这里插入图片描述

🎬 鸽芷咕:个人主页

 🔥 个人专栏: 《C++干货基地》《粉丝福利》

⛺️生活的理想,就是为了理想的生活!

引入

  哈喽各位铁汁们好啊,我是博主鸽芷咕《C++干货基地》是由我的襄阳家乡零食基地有感而发,不知道各位的城市有没有这种实惠又全面的零食基地呢?C++ 本身作为一门篇底层的一种语言,世面的免费课程大多都没有教明白。所以本篇专栏的内容全是干货让大家从底层了解C++,把更多的知识由抽象到简单通俗易懂。

⛳️ 推荐

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。

文章目录

  • 引入
  • ⛳️ 推荐
  • 一、引用的概念
    • 1.1 引用的语法
  • 二、引用的特性
    • 2.1 引用必须初始化
    • 2.2 引用不能更改指向
    • 2.3 一个变量可以有多个指向
  • 三、常引用
    • 3.1 权限的放大与缩小
    • 3.2 临时变量具有常性
  • 四、引用的使用场景
      • 做参数
      • 做返回值
    • 4.2 传值和传引用的效率对比
  • 五、引用和指针的区别
    • 5.1 引用与指针的大小
    • 5.2 引用和指针的底层对比
    • 总结
  • 📝文章结语:

一、引用的概念

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

比如:李逵,在家称为"铁牛",江湖上人称"黑旋风"。

在这里插入图片描述
所以,铁牛黑旋风,都是 李逵

  • 这俩就相当于李逵的别名

引用的概念其实有点相当于指针的平替,以往我们在使用指针等要 取地址 解引用 太麻烦了,所以C++祖师爷在开发C++的时候就有了引用的概念,下面就来看看引用到底是个什么东西吧!

1.1 引用的语法

  • 类型& 引用变量名(对象名) = 引用实体;

以上就是引用的语法了下面我们就来看一下实际是如何使用的

🍸 代码演示:

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;int main()
{int a = 10;//给a取别名int& b = a;b = 20;cout << b << endl;return 0;
}

📑代码结果:
在这里插入图片描述

这时就有很多人说了这引用不就相当于指针吗?对的引用和指针的作用其实是差不多的,对变量引用的修改会影响变量,而指针也是对指针的修改会影响指针所指向的内容:

  • 但是引用在使用上和一些场景比指针更简便更容易理解

🍸 代码演示:

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;void fun(int* x)
{*x = 20;
}void fun1(int& y)
{y = 30;
}
int main()
{int a = 10;//使用指针做形参fun(&a);cout << a << endl;//使用引用做形参fun1(a);cout << a << endl;return 0;
}

哦豁,这里我们就可以看到引用的奇妙之处了。以往我们用指针做参数的时候老是忘记去地址传参,而引用本身就是变量的别名所以,在当形参的时候我们只需要传变量就好了

  • 而在修改变量值的时候指针还要解引用才能修改
  • 而引用却可以直接修改

现在看来引用和指针对比,简直就是一个还在使用老年机一个却已经使用智能手机全自动了,别急引用的好处还在后面呢大家慢慢看完,我们在以后的项目里面可以说%80的地方都不需要指针而用引用了。

二、引用的特性

2.1 引用必须初始化

以往我们在指针定义时候老是忘记初始化而到处野指针的情况频频发生,所以祖师爷在定义引用的时候规定了引用必须初始化

🍸 代码演示:


int main()
{int a = 10;int& b = a;int& c;return 0;
}

📑代码结果:

在这里插入图片描述

2.2 引用不能更改指向

指针我们都知道是可以更改指向的,但是引用祖师爷规定了引用不能更改指向。因为C++是兼容 C语言祖师爷可能认为更改指向的事情交给 指针 做就可以了,没必要去让引用去更改指向;

🍸 代码演示:

int main()
{int a = 10;int x = 30;int& b = a;cout << b << endl;b = x;//不是改变指向而是赋值cout << b << endl;cout << a << endl;return 0;
}

📑代码结果:
在这里插入图片描述

2.3 一个变量可以有多个指向

🍸 代码演示:

int main()
{int a = 10;int& b = a;b = 20;cout << a << endl;//给别名起别名int& c = b;c = 30; cout << a << endl;return 0;
}

📑代码结果:
在这里插入图片描述

三、常引用

这里为什么会有常引用的概念呢?引用和指针一样都会去改变所指向的变量从而造成失误。而这时使用常引用就不会了

🍸 代码演示:

void fun(const int& x)
{x = 30;
}
int main()
{int a = 10;fun(a);return 0;
}

📑代码结果:
在这里插入图片描述

3.1 权限的放大与缩小

  • 权限的缩小

🍸 代码演示:

int main()
{int a = 10;//权限的缩小const int& b = a;b = 30;return 0;
}

📑代码结果:

在这里插入图片描述

这里我们就把变量 a 的别名 b 的权限缩小了,从可读可写变成了可读,所以我们就不能就行修改了

  • 权限的平移

🍸 代码演示:

int main()
{const int a = 8;//权限的平移const int& c = a;const int& b = 10;return 0;
}

平移很简单就是相同权限的变量我们就给他相同权限的别名才能使用

  • 权限的放大

在我们变成中其实权限是不能放大的,一个常量如果强行把它提升成变量是非常不安全

  • 所以权限是不能放大的

在这里插入图片描述

3.2 临时变量具有常性

这里给大家看一个代码,这里为什么int 类型可也转换为double double 却转换不了为int 引用?

在这里插入图片描述
这是因为 当我们进行赋值,或者进行隐式类型转换的时候,这里会产生一个临时变量,而临时变量具有常性

  • 是不可进行,改变和隐式类型转换的

在这里插入图片描述

  • 这是我们对其 临时变量的常性,进行权限的平移就会进行报错了
int main()
{int a = 10;double b = a;const int& x = b;return 0;
}      

那么为什么会产生临时变量?下面看一下这段代码,这里我们进行判断比较时是不会进行提升?

  • 那么这里是对变量本身进行提升吗?
int main()
{int a = 97;char b = 'a';if (a == b){cout << "a == b" << endl;}
}    

这里是对临时变量进行对比然后提升进行对比的

  • 权限放大案例
    在这里插入图片描述
int main()
{int a = 10;int b = 20;//权限的放大,a+b的结果是一个临时变量。临时变量具有常性//int& b = a + b;const int& b = a + b;return 0;
}      

四、引用的使用场景

看到这里其实大家,都知道指针和引用的功能大致相同

  • 但是 C++ 的引用是为了替换掉一下指针复杂场景的替换使代码,使代码更加简介但是引用不能代替指针
  • 他们更多的是相辅相成

做参数

引用的更多使用场景就是传参来用的,以往我们在使用指针更改指针指向的变量,或者二级指针使用起来太不方便了,但是使用引用就非常简单:

void swap(int& x, int& y)
{int tmp = x;x = y;y = tmp;
}int main()
{int a = 10;int b = 20;swap(a, b);cout << a << endl;cout << b << endl;return 0;
}

以往我们在进行交换函数的使用每次都需要,取地址进行传参,而有了引用的概念用起来就方便多了

做返回值

📑 错误示范:

int& fun()
{int a = 10;return a;
}int& fx()
{int b = 20;return b;
}int main()
{int& a = fun();cout << a << endl;fx();cout << a << endl;return 0;
}

这里我们就错误的使用引用做返回值的,我们吧函数 fun 里面本来要销毁的变量给使用别名返回了。但是这个快空间本来是要还给操作系统的:

  • 这样我们就造成了内存泄漏
  • 当我们在进行调用函数时会对上一个销毁的函数空间进行复用,所以就把原来的空间a给改变了

在这里插入图片描述

🔥 所以使用引用做返回值的时候一定是对在堆上开辟,或者动态开辟的空间不会随着函数销毁而销毁的空间才可以用引用做返回值

  • 如果不是动态开辟的空间或者再堆上开辟的空间,会随着函数的销毁而销毁就一定要用传值传参

这里在顺序表里面如果把 Get 获取函数指定位置的值进行传引用返回的话就可以把修改循序表的的 Modity 给干掉了

  • 一个函数既可以获取值又可以修改值

struct SeqList
{int* a;int size;int capacity;//成员函数void Init(SeqList& sl){int* tmp = (int*)malloc(sizeof(int) * 4);if (tmp == NULL){perror("malloc file");exit(-1);}sl.a = tmp;sl.size = 0;sl.capacity = 4;}void PushBack(SeqList& sl,int x){//...sl.a[size++] = x;}int& Get(SeqList& sl, int pos){return sl.a[pos];}
};
int main()
{SeqList s;s.Init(s);s.PushBack(s, 1);s.PushBack(s, 2);s.PushBack(s, 3);s.PushBack(s, 4);for (int i = 0; i < s.size; i++){cout << s.Get(s, i) << " ";}cout << endl;for (int i = 0; i < s.size; i++){s.Get(s, i) *= 2;cout << s.Get(s, i) << " ";}cout << endl;cout << endl;return 0;
}

4.2 传值和传引用的效率对比

函数在进行传值做形参的话,形参是实参的一份临时拷贝。所以对系统的空间是有一定消耗的,当我们调用函数次数多的话就在效率上就会有一定影响,从而降低效率:

  • 下面我们就来测试一下传值调用和传引用调用的效率吧!
#include <time.h>
struct A { int a[10000]; };
void TestFunc1(A a) {}
void TestFunc2(A& a) {}
void TestRefAndValue()
{A a;// 以值作为函数参数size_t begin1 = clock();for (size_t i = 0; i < 10000; ++i)TestFunc1(a);size_t end1 = clock();// 以引用作为函数参数size_t begin2 = clock();for (size_t i = 0; i < 10000; ++i)TestFunc2(a);size_t end2 = clock();// 分别计算两个函数运行结束后的时间cout << "TestFunc1(A)-time:" << end1 - begin1 << endl;cout << "TestFunc2(A&)-time:" << end2 - begin2 << endl;
}int main()
{TestRefAndValue();return 0;
}

🔥 在这里我们调用一万次他们的差别分别是 8毫秒多 和 0毫秒

在这里插入图片描述

五、引用和指针的区别

5.1 引用与指针的大小

🍸 代码演示:

int main()
{int a = 10;int& b = a;int* c = &a;cout << "引用大小:" << sizeof(a) << endl;cout << "指针大小:" << sizeof(c) << endl;cout << "int大小:" << sizeof(int) << endl;cout << "longlong大小:" << sizeof(long long) << endl;cout << "引用大小:" << sizeof(long long&) << endl;cout << "指针大小:" << sizeof(long long*) << endl;return 0;
}

📑代码结果:
在这里插入图片描述
🔥 在sizeof中:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节)

5.2 引用和指针的底层对比

这边我们定义一个指针和引用,然后我们把它转成汇编代码会发现他们来生成的汇编代码是一样的

  • 🔥 所以在底层,引用和指针都是一回事,引用是按照指针方式来实现的。

在这里插入图片描述

总结

引用和指针的底层对比

  1. 在语法上引用是给一个变量起别名,不开空间。指针是把一个变量的地址存起来。

  2. 引用必须初始化才能使用,指针可以初始化也可以不初始化

  3. 引用不可以改变指向,但指针可以改变指向

  4. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32
    位平台下占4个字节)

  5. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小

  6. 有多级指针,但是没有多级引用

  7. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理

  8. 引用比指针使用起来相对更安全

底层上:

🔥 在底层上引用是开辟空间的,因为引用是用指针实现的

📝文章结语:

☁️ 看到这里了还不给博主扣个:
⛳️ 点赞🍹收藏 ⭐️ 关注
💛 💙 💜 ❤️ 💚💓 💗 💕 💞 💘 💖
拜托拜托这个真的很重要!
你们的点赞就是博主更新最大的动力!

在这里插入图片描述

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

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

相关文章

MYSQL的配置和安装

下载安装 打开官网 MYSQL官网 点击DOWNLOADS 滑到最低下点击&#xff1a;MYSQL Community(GPL) Downlads 点击Download Archives 点击MySQL Community Server进入网站 选择相应版本下载&#xff0c;这里选择的是5.7.24版本,x86 64位【按需选择】 下载解压 配置文件…

GitLab16.8配置webhooks、Jenkins2.4配置GitLab插件实现持续集成、配置宝塔面板实现持续部署(其三)

看本篇文章的前提是已经部署完GItlab和Jenkins服务器&#xff0c;已经可以手动构建成功&#xff0c;并且经过了很多次实践&#xff0c;对这两款软件基本熟悉。 建议大家按以下顺序看 前端自动化&#xff08;其一&#xff09;部署gitlab 前端自动化&#xff08;其二&#xff0…

LeetCode--171

171. Excel 表列序号 给你一个字符串 columnTitle &#xff0c;表示 Excel 表格中的列名称。返回 该列名称对应的列序号 。 例如&#xff1a; A -> 1 B -> 2 C -> 3 ... Z -> 26 AA -> 27 AB -> 28 ... 示例 1: 输入: columnTitle "A" 输出:…

设计模式⑩ :用类来实现

文章目录 一、前言二、Command 模式1. 介绍2.应用3. 总结 三、Interpreter 模式1. 介绍2. 应用3. 总结 参考文章 一、前言 有时候不想动脑子&#xff0c;就懒得看源码又不像浪费时间所以会看看书&#xff0c;但是又记不住&#xff0c;所以决定开始写"抄书"系列。本系…

【JS逆向实战-入门篇】某gov网站加密参数分析与Python算法还原

文章目录 1. 写在前面2. 请求分析3. 断点分析4. 算法还原 【作者主页】&#xff1a;吴秋霖 【作者介绍】&#xff1a;Python领域优质创作者、阿里云博客专家、华为云享专家。长期致力于Python与爬虫领域研究与开发工作&#xff01; 【作者推荐】&#xff1a;对JS逆向感兴趣的朋…

PPT、PDF全文档翻译相关产品调研笔记

主要找一下是否有比较给力的全文档翻译 文章目录 1 百度翻译2 小牛翻译3 腾讯交互翻译4 DeepL5 languagex6 云译科技7 快翻:qtrans8 simplifyai9 officetranslator10 火山引擎翻译-无文档翻译1 百度翻译 地址: https://fanyi.baidu.com/ 配套的比较完善,对于不同行业也有区…

【大厂AI课学习笔记】1.3 人工智能产业发展(2)

&#xff08;注&#xff1a;腾讯AI课学习笔记。&#xff09; 1.3.1 需求侧 转型需求&#xff1a;人口红利转化为创新红利。 场景丰富&#xff1a;超大规模且多样的应用场景。主要是我们的场景大&#xff0c;数据资源丰富。 抗疫加速&#xff1a;疫情常态化&#xff0c;催生新…

DataX介绍

一、介绍 DataX 是一个异构数据源离线同步工具&#xff0c;致力于实现包括关系型数据库(MySQL、Oracle等)、HDFS、Hive、ODPS、HBase、FTP等各种异构数据源之间稳定高效的数据同步功能。 github地址 详细文档 操作手册 支持数据框架如下&#xff1a; 架构 Reader&#xff1…

干货!收藏!一文讲清楚数据治理到底是什么?

数据治理的两个目标&#xff1a;一个是提质量&#xff0c;一个是控安全。通过业务流程优化&#xff0c;规范数据从产生、处理、使用到销毁的整个生命周期&#xff0c;使得数据在各阶段、各流程环节安全可控&#xff0c;合规使用。 数据治理治的是“数据”吗&#xff1f; 数据是…

Ubuntu搭建国标平台wvp-GB28181-pro

目录 简介安装和编译1.查看操作系统信息2.安装最新版的nodejs3.安装java环境4.安装mysql5.安装redis6.安装编译器7.安装cmake8.安装依赖库9.编译ZLMediaKit9.1.编译结果说明 10.编译wvp-GB28181-pro10.1.编译结果说明 配置1.WVP-PRO配置文件1.1.Mysql数据库配置1.2.REDIS数据库…

GPT-5的功能界面曝光。。。

最近网络上流传的照片是否真实尚不可知&#xff0c;我们需要进一步的核实与分析。 GPT-5的预期发布已经引起了业界的极大关注。根据Roemmele的透露&#xff0c;GPT-5将是一个革命性的多模态模型&#xff0c;能够支持语音、图像、编程代码和视频等多种格式&#xff0c;这标志着…

【Linux】多线程(线程概念+线程控制)

&#x1f307;个人主页&#xff1a;平凡的小苏 &#x1f4da;学习格言&#xff1a;命运给你一个低的起点&#xff0c;是想看你精彩的翻盘&#xff0c;而不是让你自甘堕落&#xff0c;脚下的路虽然难走&#xff0c;但我还能走&#xff0c;比起向阳而生&#xff0c;我更想尝试逆风…

负载均衡下的webshell上传+nginx解析漏洞

负载均衡下的webshell上传 一&#xff0c;负载均衡下webshell上传的四大难点 难点一&#xff1a;需要在每一台节点的相同位置上传相同内容的webshell 我们需要在每一台节点的相同位置都上传相同内容的 WebShell一旦有一台机器上没有&#xff0c;那么在请求轮到这台机器上的时…

二分查找-迭代法

Go 算法 每天5道&#xff0c;开心快乐每一天 一点都不开心 哈哈哈哈哈哈 -2.1 day 1 1.22&#xff08;1.23 1.25 1.29&#xff09; 1.23 已复习 704. 二分查找 力扣题目链接 //左闭右开 func search(nums []int, target int) int { right : len(nums) left : 0; for le…

React18-模拟列表数据实现基础表格功能

文章目录 分页功能分页组件有两种接口参数分页类型用户列表参数类型 模拟列表数据分页触发方式实现目录 分页功能 分页组件有两种 table组件自带分页 <TableborderedrowKey"userId"rowSelection{{ type: checkbox }}pagination{{position: [bottomRight],pageSi…

海外多语言盲盒App开发:机遇与挑战并存

随着全球化进程的加速&#xff0c;跨文化交流成为人们日常生活和工作中的重要部分。在此背景下&#xff0c;多语言盲盒App的开发成为了一个具有巨大潜力的市场。本文将探讨海外多语言盲盒App开发的机遇与挑战&#xff0c;以及如何应对这些挑战。 一、海外多语言盲盒App开发的机…

AI赋能编程 | 自动化工具助力高效办公

前言 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家&#xff1a;https://www.captainbed.cn/z ChatGPT体验地址 文章目录 前言泡泡AI工具卡片思维导图Markdown编辑器 其他工具文件免费处理工具结语 合集…

C++引用详解

顾得泉&#xff1a;个人主页 个人专栏&#xff1a;《Linux操作系统》 《C/C》 《LeedCode刷题》 键盘敲烂&#xff0c;年薪百万&#xff01; 一、引用的概念 引用不是新定义一个变量&#xff0c;而是给已存在变量取了一个别名&#xff0c;编译器不会为引用变量开辟内存空间…

使用 Paimon + StarRocks 极速批流一体湖仓分析

摘要&#xff1a;本文整理自阿里云智能高级开发工程师王日宇&#xff0c;在 Flink Forward Asia 2023 流式湖仓&#xff08;二&#xff09;专场的分享。本篇内容主要分为以下四部分&#xff1a; StarRocksPaimon 湖仓分析的发展历程使用 StarRocksPaimon 进行湖仓分析主要场景和…

RPC教程 7.服务发现与注册中心

0.前言 这一节的内容只能解决只有一个服务的情况。要是有多个服务(即是多个结构体&#xff09;这种就解决不了&#xff0c;也即是没有服务ip地址和服务实例的映射关系。 1.为什么需要注册中心 在上一节中&#xff0c;客户端想要找到服务实例的ip,需要硬编码把ip写到代码中。…