【C++】C++入门基础:引用详解

news2024/11/15 19:29:31

本篇继续分享关于C++入门的相关知识,有关命名空间、缺省参数和函数重载的部分欢迎阅读我的上一篇文章【C++】C++入门基础详解(1)_王笃笃的博客-CSDN博客

继续我们的学习

引用

在C语言中我们接触过指针,很多人都或多或少为他感到头痛过,很多C语言的使用者包括创始人都觉得很难用,所以便创造出了引用。

1.引用的概念

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

举个例子,就比如你叫李四,同学给你起了外号叫小四,你妈妈给你取的小名叫四四,这些名字都指的是李四,这么说应该不难理解;

上代码感受一下

int main()
{
	int a = 0;
	int& b = a;

	return 0;
}

可以看到我们创建出了一个整形a,使用&符号创建了b,这里的b就是a的别名,他们公用一段内存空间。

很明显&符号在类型和定义的变量中间会被当作引用符号,否则就是取地址,我们也可以看出a和b共用同一块空间;

当我们给a和b同时++运算时

 可以看到他们都参与了运算,因为他们本质上就是对同一个数据进行操作;

可以简单的使用在两数交换之中

 可以看到传值并不会真正的实现转换,但是我们用引用的方法传参

 

 可以看到两数交换成功了。

在这里里我们在函数中用引用定义参数意义是给实参取了别名,x的别名就是a,y的别名就是b,我们对a和b进行操作实际上就是对x和y进行操作。

还有一种用C语言实现链表的场景

typedef struct ListNode
{
	int val;
	struct ListNode* next;
}ListNode;

void Push_back(ListNode** pphead, int x)
{
	ListNode* newnode = (ListNode*)malloc(sizeof(ListNode) * sizeof(int));
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{

	}
}
int main()
{
	ListNode* plist = NULL;
	Push_back(&plist, 1);
	Push_back(&plist, 2);
	Push_back(&plist, 3);
}

这里的重点是二级指针的使用,当时我在写二级指针的时候也是非常头疼,但是我我们现在学习了引用可以对上面的代码进行优化;

typedef struct ListNode
{
	int val;
	struct ListNode* next;
}ListNode;

void Push_back(ListNode*& phead, int x)
{
	ListNode* newnode = (ListNode*)malloc(sizeof(ListNode) * sizeof(int));
	if (phead == NULL)
	{
		phead = newnode;
	}
	else
	{

	}
}
int main()
{
	ListNode* plist = NULL;
	Push_back(plist, 1);
	Push_back(plist, 2);
	Push_back(plist, 3);
}

可以看到现在的phead就是plist的别名,也就是说操作phead就可以达到操作plist的目的,这样就不用再纠结二级指针的使用,同样可以达到二级指针的效果。

通过以上代码我们可以知道引用作为形参,其他函数传参时引用可以影响实参。

接下来是引用使用时需要注意的一些小细节;

2.引用的特性

使用引用的时候必须初始化

 不能说只取外号没有真正的名字,这样的用法是错误的;

同时一个变量可以被多次引用,也就是说一个人可以有很多个外号,也可以给外号取外号;

int main()
{
	int a = 0;
	int& b = a;
	int& c = a;
	int& d = a;
	int& e = d;

	return 0;
}

这些都是可行的,虽然有很多引用但是它的底层都是对a进行操作;

还需要注意的是引用一但引用了一个实体,就不能再引用其他实体,也就是说上面的b、c、d、e不能再当作别人的外号。

 

可以看到报错说e被多次初始化,这也是C++的引用和java的引用区别,C++的引用只能引用一个实体,java的引用是可以改变指向的,这样就导致C++不能脱离指针,Java可以脱离指针。

3.引用做返回值

在刚开始认识函数时我们接触过传值返回

需要注意的是这里返回值并不是n,而是n的值 

 同时也有一种用法,但是这种用法非常危险。

那就是函数传引用返回

int& Count()
{
	int n = 0;
	n++;
	return n;
}

int main()
{
	int ret = Count();
	cout << ret << endl;
	return 0;
}

为什么会这种用法会非常危险呢?

我们知道调用函数时会建立栈帧,函数内部的临时变量都会在调用函数结束时失效,在这里传引用返回就相当于给没有名字的空间起了别名,类似于野指针的后果,所以这种情况输出可能会有两种情况,一种是正常输出,一种会输出随机值

 

可以看到在vs的平台下会输出1,但是下方的结果或有一个waring

 

 我们再用一段代码来解释传引用返回的影响;

int& Add(int x, int y)
{
	int c = x + y;
	return c;
}

int main()
{
	int& ret = Add(1,2);
	Add(2, 3);
	cout << "Add(1,2) is" << ret << endl;
	return 0;
}

以下是运行结果

 这里的原因是先用1和2调用了Add函数,并且将此次调用函数所占用的空间取了别名叫做ret,此时Add函数除了作用域后里面的数值都会被销毁,而空间还会被留下来,此时再次用2和3去调用Add,那么此次调用就会使用Add的栈帧空间,就得到了如上结果。

形象的说就是你在某一家酒店开了房,走的时候发现有东西没拿上,所以重新回房间里拿了东西,希望大家可以理解。

所以分享了以上错误的使用方式可以得到一个结论:如果函数返回时,出了函数作用域,如果返回对象没有返还给系统,则可以使用引用返回;如果已经返还给系统,则必须使用传值返回。

传引用返回在有些场景下也有着便捷的作用;

当初在学习数据结构时使用C语言完成链表是非常繁琐的

这里简单使用链表找到第i个位置的数据和修改数据

struct SeqList
{
	int* a;
	int size;
	int capacity;
};
//找到第i个位置
int SLAt(SeqList* ps, int i)
{
	assert(i < ps->size);
	return ps->a[i];
}
//修改
int SLModify(SeqList* ps, int i,int x)
{
	assert(i < ps->size);
	ps->a[i]=x;

}

可以感觉到C语言的接口非常的繁琐;

下面是C++读或修改数据的接口

 

int& SLAt(SeqList* ps, int i)
{
	assert(i < ps->size);
	return ps->a[i];
}

可以看到非常非常简单,只需要在返回类型前加上引用符号即可完成读取和修改的操作,

当然也可也全部使用引用减少拷贝的时间消耗

int& SLAt(SeqList& ps, int i)
{
	assert(i < ps.size);
	return ps.a[i];
}

通过main函数来简单使用

 这样我们既可以完成读取

也可以完成修改操作

所以引用做返回值也有它合适的场景。

以上就是本片要分享的关于C++引用的使用,如果对你有所帮助还请三连支持,感谢您的阅读。

 

 

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

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

相关文章

开源后台管理系统Geekplus Admin

本系统采用前后端分离开发模式&#xff0c;后端采用springboot开发技术栈&#xff0c;mybatis持久层框架&#xff0c;redis缓存&#xff0c;shiro认证授权框架&#xff0c;freemarker模版在线生成代码&#xff0c;websocket消息推送等&#xff0c;后台管理包含用户管理&#xf…

1122.数组的相对排序

目录 一、题目 二、分析代码 一、题目 二、分析代码 核心计数排序&#xff01;&#xff01;&#xff01; class Solution { public: vector<int> relativeSortArray(vector<int>& arr1, vector<int>& arr2) {int n arr1.size();int arr1_Max I…

C++ string类详解

⭐️ string string 是表示字符串的字符串类&#xff0c;该类的接口与常规容器的接口基本一致&#xff0c;还有一些额外的操作 string 的常规操作&#xff0c;在使用 string 类时&#xff0c;需要使用 #include <string> 以及 using namespace std;。 ✨ 帮助文档&…

USB隔离器电路分析,SA8338矽塔sytatek电机驱动,源特科技VPS8701,开关电源,电源 大师

一、 USB隔离器电路分析 进行usb隔离可以使用USB隔离模块 ADUM3160 ADUM4160 注意&#xff1a;B0505S 最大带载0.16A&#xff0c;副边需要带载能力需要改变方案 比如移动硬盘至少需要0.5A 用充电宝、18650、设计5V1A输出电源 二、 1A隔离电压方案

【蓝桥杯】[递归]母牛的故事

原题链接&#xff1a;https://www.dotcpp.com/oj/problem1004.html 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 我们列一个年份和母牛数量的表格&#xff1a; 通过观察&#xff0c;找规律&#xff0c;我们发现&#xff1a; 当年份小于等于4时&…

Linux环境下python连接Oracle教程

下载Oracle client需要的 安装包 rpm包下载地址&#xff1a;Oracle官方下载地址 选择系统版本 选择Oracle版本 下载3个rpm安装包 oracle-instantclient12.2-basic-12.2.0.1.0-1.i386.rpm oracle-instantclient12.2-devel-12.2.0.1.0-1.i386.rpm oracle-instantclient12.2-sq…

算法通关村第八关——轻松搞定二叉树的深度和高度问题

1.基础知识 二叉树节点的高度&#xff1a;指从当前节点到叶子节点的最长简单路径边的条数 二叉树节点的深度&#xff1a;指从根节点到当前节点的最长简单路径边的条数 二叉树的深度和高度问题&#xff0c;递归思想的运用很是普遍&#xff0c;有的问题层序遍历也可以解决。 2.最…

PyTorch Lightning:通过分布式训练扩展深度学习工作流

一、介绍 欢迎来到我们关于 PyTorch Lightning 系列的第二篇文章&#xff01;在上一篇文章中&#xff0c;我们向您介绍了 PyTorch Lightning&#xff0c;并探讨了它在简化深度学习模型开发方面的主要功能和优势。我们了解了 PyTorch Lightning 如何为组织和构建 PyTorch 代码提…

3种获取OpenStreetMap数据的方法【OSM】

OpenStreetMap 是每个人都可以编辑的世界地图。 这意味着你可以纠正错误、添加新地点&#xff0c;甚至自己为地图做出贡献&#xff01; 这是一个社区驱动的项目&#xff0c;拥有数百万注册用户。 这是一个社区驱动的项目&#xff0c;旨在在开放许可下向每个人提供所有地理数据。…

基于YOLOv8模型的奶牛目标检测系统(PyTorch+Pyside6+YOLOv8模型)

摘要&#xff1a;基于YOLOv8模型的奶牛目标检测系统可用于日常生活中检测与定位奶牛目标&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的目标检测&#xff0c;另外本系统还支持图片、视频等格式的结果可视化与结果导出。本系统采用YOLOv8目标检测算法训练数据集…

【小梦C嘎嘎——启航篇】vector 以及日常使用的接口介绍

【小梦C嘎嘎——启航篇】vector 日常使用的接口介绍&#x1f60e; 前言&#x1f64c;vector 是什么&#xff1f;vector 比较常使用的接口 总结撒花&#x1f49e; &#x1f60e;博客昵称&#xff1a;博客小梦 &#x1f60a;最喜欢的座右铭&#xff1a;全神贯注的上吧&#xff01…

Parking Steps

上面是老师傅说的停车步骤&#xff0c;说这样不会伤变速箱。 平时就是&#xff0c;脚踩刹车&#xff0c;直接从D档撸到P档&#xff0c;拉手刹&#xff0c;哈哈。 你的停车步骤是啥。。

redis 存储结构原理 2

咱们接着上一部分来进行分享&#xff0c;我们可以在如下地址下载 redis 的源码&#xff1a; https://redis.io/download 此处我下载的是 redis-6.2.5 版本的&#xff0c;xdm 可以直接下载上图中的 **redis-6.2.6 **版本&#xff0c; redis 中 hash 表的数据结构 redis hash …

php_mb_strlen指定扩展

1 中文在utf-字符集下占3个字节,所以计算出来长度为9。 2 可以引入php多字节字符的扩展&#xff0c;默认是没有的&#xff0c;需要自己配置这个函数 3 找到php.ini文件&#xff0c;去掉;extension mbstring的注释&#xff0c;接着重启apache服务 可以看到准确输出的中文的长度…

javascript期末作业【三维房屋设计】

1、引入three.js库 官网下载three.js 库 放置目录并引用 引入js文件: 设置场景&#xff08;scene&#xff09; &#xff08;1&#xff09;创建场景对象 &#xff08;2&#xff09;设置透明相机 1,透明相机的优点 透明相机机制更符合于人的视角,在场景预览和游戏场景多有使用…

视频怎么转gif高清动图?分享一款视频转gif工具

许多小伙伴都不知道如何将拍摄的短视频转gif图片&#xff0c;本文将分享一款专业的视频转gif工具&#xff0c;打来浏览器即可将视频在线转gif&#xff08;https://www.gif.cn&#xff09;&#xff0c;操作简单&#xff0c;使用方便&#xff0c;下面是详细的步骤。 打开网站&am…

SpringBoot案例-员工管理-新增员工

查看页面原型&#xff0c;明确需求 页面原型 需求 阅读接口文档 接口文档链接如下&#xff1a; 【腾讯文档】SpringBoot案例所需文档 https://docs.qq.com/doc/DUkRiTWVaUmFVck9N 思路分析 阅读需求文档后可知&#xff0c;前端发送请求的同时&#xff0c;将前端请求参数以…

centos8 使用phpstudy安装tomcat部署web项目

系统配置 1、安装Tomcat 2、问题 正常安装完Tomcat应该有个配置选项&#xff0c;用来配置server.xml web.xml 还有映射webapps路径选项&#xff0c;但是我用的这个版本并没有。所以只能曲线救国。 3、解决 既然没有配置项&#xff0c;那就只能按最基本的方法配置&#xff0c…

算法之排序总结

排序算法 最近&#xff0c;一直在学习业务上的知识&#xff0c;对基础没有怎么重视&#xff0c;因此&#xff0c;这篇文章想对于排序算法进行一个大致的总结&#x1f913;&#x1f913;&#x1f913;。 首先来说一下&#xff0c;关于排序一些相关的基础知识。 排序概述 原地…

代码随想录第25天|216.组合总和III ​​​​​​​,17. 电话号码的字母组合

216.组合总和III 回溯三部曲 确定递归函数参数 targetSum&#xff08;int&#xff09;目标和&#xff0c;也就是题目中的n。k&#xff08;int&#xff09;就是题目中要求k个数的集合。sum&#xff08;int&#xff09;为已经收集的元素的总和&#xff0c;也就是path里元素的…