探索C嘎嘎的奇妙世界:第四关---引用与内联函数
1 引用:
引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。
#include<iostream>
using namespace std;int main()
{int a = 0;// 引用:b是a的别名int& b = a;int& c = a;int& d = b;++d;cout << &a << endl;cout << &b << endl;cout << &c << endl;cout << &d << endl;return 0;
}
在上述代码中,我们定义了一个整型变量a=0,然后,这样"int&b=a"定义了一个b,这时就有小伙伴看不懂了?这个"&",不是C语言中的取地址吗?这是什么意思?
类型& 引用变量名(对象名) = 引用实体,在C++中,"&"被我们的祖师爷赋予了另一种含义"引用"
引用是给对象起的一个别名,它也是一种复合类型。通过将声明符写成 &d 的形式来定义引用类型,其中 d 是声明的变量名。定义引用时,程序把引用和它的初始值绑定在一起,而不是将初始值拷贝给引用。一旦初始化完成,引用将和它的初始值对象一直绑定在一起。因此引用必须初始化,而且引用不能重新绑定到另一个对象,类型要和绑定的类型一致。引用本身不是独立的数据类型,所以不占用空间,引用的地址就是对象的地址。也就无法定义指向引用的指针,无法声明存储引用类型的数组等.
在上述代码中,小伙伴们,可以看到b和c都是对a的引用,d是对a的引用,那我们对d进行++操作,会不会改变其他几个呢?
当然,上面说了,引用就相当于起了个别名,比如:小三是张三的别名,小三吃饭了,那我们猜猜张三吃饭了吗?,肯定也吃了呀.所以引用只是给他换了一个名字,但其实还是本身,所以对d进行++会对其它所有别名进行改变.
那么引用是用来干嘛的呢?请看下面代码:
void Swap(int* a, int* b)
{int tmp = *a;*a = *b;*b = tmp;
}void Swap(int& a, int& b)
{int tmp = a;a = b;b = tmp;
}int main()
{int a=10,b=20;//Swap(&a,&b);//第一种Swap(a,b);//第二种return 0;
}
在上述代码中,第一种方法想必是大多数小伙伴常用的指针,那么第二种就是我们今天要学习的"引用"从定义角度和调用角度,二者都有所差距.指针是通过传地址进行改变,而引用是通过给实参取别名,从而进行交换,需要注意的是引用的地址和数据本身的地址是相同的.看起来是不是引用用起来更加方便了?
同时指针不止能给一些内置类型取别名,还能给指针取别名哦~
int main()
{int x = 0;int* p1 = &x;int*& pr = p1;pr = NULL;return 0;
}
在上述代码中,我们用一个指针p1去存储x的地址,用pr去给p1套了一层引用,然后对pr进行置空,这样p1也就置空了.所以这样来看引用还是挺好的
1.1引用的特性:
1. 引用在定义时必须初始化
void TestRef()
{int a = 10;// int& ra; // 该条语句编译时会出错int& ra = a;int& rra = a;printf("%p %p %p\n", &a, &ra, &rra);
}
上述代码中如果只是定义一个:"int& ra"而不对其进行初始化的话,编译器会报错,取别名总要有一个主体吧
2. 一个变量可以有多个引用
1.2 常引用:
int main()
{ // 权限的平移int x = 0;int& y = x;// 权限的缩小,可以const int& z = x;//z++; // 不可以y++;//可以// 权限的放大// m只读// n变成我的别名,n的权限是可读可写// 权限的放大,不可以const int m = 0;// int& n = m;const int& n = m;return 0;
}
上述代码中,第一处:定义了一个int型的x=0,然后给x取了一个别名y,,都是可读可写的, 这样写是合乎语法的;
第二处:定义了一个const int的z并且给x取别名了,这样写是相当于权限的缩小,因为x是可读可写的,而z是只能读,所以z的权限被缩小了,完全是可以的,同时要注意,我们不能通过z去进行修改,只能通过y去修改,那么就有小伙伴要问了,y改变了,z变了吗?先给结论,z也会跟着变,为什么呢?因为const只是不能去直接修改它所修饰的变量,但是可以间接的去修改;
第三处:定义了一个const int 型的m,然后定义了一个int型的n给m进行取别名,可不可以呢?肯定是不行的嘛.因为m是只能读不能写的,而n是可读可写的,这样就权限放大了不合乎语法会报错,只有把n也该成const int型的才可以,相当于权限的平移.
关于引用的东西远不于此过不了多久就会再次相见~~~
1.3 引用的探讨:
那我们再探讨一个问题:引用开不开空间呢?
这个问题我们可以从汇编层次来看:
从这里我们可以看出,在汇编层次上来看,指针和引用好像是你"亲兄弟"一样,哈哈~是的,它们在汇编层面只是寄存器不同,其他都相同,我们都知道指针是开空间的,所以我们可以得出结论了:
结论:引用在会汇编层面是和指针一样需要开空间的,但是我们在语法上通常认为引用是不开空间的.
1.4 引用与指针的对比及优缺点:
1.4.1 引用和指针的对比:
10.内存占用:引用不占内存,而指针占用内存。
11.数组和指针:不能声明引用数组,可以声明指针数组。
12.引用的引用:不能定义引用的引用,而可以定义指针的指针。
1.4.2 引用的优点:
1.性能更好:引用的性能可能会更好,因为指针会导致变量在栈里一定会有地址,可能会引起反复解引用的问题,而引用可以让无需压栈的变量一直在寄存器里,不生成地址。
2.更安全:引用本身是目标变量或对象的别名,对引用的操作本质上就是对目标变量或对象的操作。因此能使用引用时尽量使用引用而非指针。
1.4.3 指针的优点:
1.灵活性高:指针可以指向任意类型的对象,并且可以在运行时动态地改变指向的对象。
2.可以为空:指针可以为空,这在某些情况下是很有用的,例如表示一个不存在的对象或者表示一个结束标志。
总的来说,引用和指针都有各自的优缺点,在使用时需要根据具体情况进行选择。如果需要高效地传递大型对象或者需要在函数内部修改外部变量的值,引用是一个不错的选择。如果需要灵活地操作对象或者需要处理动态分配的内存,指针可能更合适。
2 内联函数:
2.1 内联函数的概念:
内联函数是在程序编译时,编译器会将内联函数的代码直接嵌入到调用它的地方,而不是像普通函数那样进行函数调用的一系列操作(如建立栈帧等)。
如果在上述函数前增加inline关键字将其改成内联函数,在编译期间编译器会用函数体替换函数的调用。
查看方式:
1. 在release模式下,查看编译器生成的汇编代码中是否存在call Add


2.2 内联函数的特性:
1. inline是一种以空间换时间的做法,如果编译器将函数当成内联函数处理,在编译阶段,会 用函数体替换函数调用,缺陷:可能会使目标文件变大,优势:少了调用开销,提高程序运 行效率。
2. inline对于编译器而言只是一个建议,不同编译器关于inline实现机制可能不同,一般建 议:将函数规模较小(即函数不是很长,具体没有准确的说法,取决于编译器内部实现)、不 是递归、且频繁调用的函数采用inline修饰,否则编译器会忽略inline特性。下图为

// F.h
#include <iostream>
using namespace std;
inline void f(int i);
// F.cpp
#include "F.h"
void f(int i)
{cout << i << endl;
}// main.cpp
#include "F.h"
int main()
{f(10);return 0;
}
在上述代码中,如果强行对内联函数进行声明和定义分离,那么编译器会报一个这样的错误:
// 链接错误:main.obj : error LNK2019: 无法解析的外部符号 "void __cdecl f(int)" (?f@@YAXH@Z),该符号在函数 _main 中被引用
总结:短小函数定义 换用内联函数
编译器并不一定会完全按照开发者的意愿将函数内联,它会根据实际情况(如函数的复杂性等)来决定是否真正进行内联操作。总的来说,内联函数是一种优化技术,旨在提高程序的性能和可读性,但需要合理使用以避免潜在的问题。
到此为止,有关引用和内联函数的讲解就结束了~希望这篇博客能给您带来一些启发和思考!那我们下次再一起探险喽,欢迎在评论区进行讨论~~~
相关文章:

探索C嘎嘎的奇妙世界:第四关---引用与内联函数
1 引用: 引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。 #include<iostream> using namespace std;int main() {int a 0;// 引用:…...

DLS平台:惠誉全球经济展望——今年调增至2.6%,明年调减!
摘要 尽管全球货币政策逐渐转向宽松,惠誉国际评级(Fitch Ratings)在最新的《全球经济展望》中对2024年全球经济增长进行了上调。然而,由于美国经济增速放缓和其他因素的影响,2025年的全球经济增长预期则被下调。这篇文…...

数据结构习题
第一章 绪论 与数据元素本身的形式、内容、相对位置、个数无关的是数据的 逻辑结构。 第二章 线性表 在一个有127个元素的顺序表中插入一个新元素并保持原来顺序不变,平均要移动的元素个数为 63.5。 n/2 单链表的存储密度 小于1。 创建一个包括n个结点的有序单链…...
交通银行软件开发工程师校招面试经历
本文介绍2024届春招中,交通银行总行的软件开发工程师岗位1场面试的基本情况、提问问题等。 2024年04月投递了交通银行总行的软件开发工程师岗位,暂时不清楚所在部门。目前完成了一面,并进入体检阶段;在这里记录一下面试的相关经历…...
bashrc和profile区别
作用与目的: .bashrc:这个文件主要用于配置和自定义用户的终端环境和行为。每次启动新的终端时,.bashrc文件都会被执行,加载用户设置的环境变量、别名、函数等。这使得用户能够根据自己的喜好和需求来定制终端的行为和外观。profi…...

BC153 [NOIP2010]数字统计
数字统计 一.题目描述二.输入描述:三.输出描述:四.数字范围五.题目思路六.代码实现 一.题目描述 请统计某个给定范围[L, R]的所有整数中,数字2出现的次数。 比如给定范围[2, 22],数字2在数2中出现了1次,在数12中出现1次…...
浅谈LavelDB
简介 LevelDB 是一个开源的轻量级键值存储库,由 Google 开发,用于提供快速的键值存储和支持读写大量数据。LevelDB 具有高性能、快速的读取和写入速度以及支持原子操作的特点,适合用于需要高效存储和检索键值数据的场景。 LevelDB 主要特点…...

Google Earth Engine(GEE)——NDVI的时间序列分析和在线出图
函数: ui.Chart.array.values(array, axis, xLabels) Generates a Chart from an array. Plots separate series for each 1-D vector along the given axis. - X-axis = Array index along axis, optionally labeled by xLabels. - Y-axis = Value. - Series = Vector, d…...
谈吐的艺术(三)
不是要逼人屈服,而只是想请人遵守规定。 0可能遇到的问题 在快餐店买到的汉堡和薯条都是凉的,跟店员理论的时候对方却说味道没有不对。怎么说才能维护自己的权利呢? 更好的说法:“我想问一下,按照你们的规定,食品退换…...

pop链详细分析、构造(以[NISACTF 2022]babyserialize为例)
目录 [NISACTF 2022]babyserialize (一)理清pop链(链尾 链头),标注步骤 1. 先找eval、flag这些危险函数和关键字样(这是链尾) 2.往eval()上面看 3.往$bb()上面看 4.往strtolower()上面看 …...

使用超声波麦克风阵列预测数控机床刀具磨损
预测性维护是使用传感器数据来推断机器状态,并从这些传感器数据中检测出在故障发生之前存在的缺陷或故障的过程。预测性维护在所有工业领域都是一种日益增长的趋势,包括轴承故障检测、齿轮磨损检测或往复式机器中的活塞磨损等许多其他例子。在预测性维护…...

怎么控制多个存储设备的访问权限?数据安全存储方案来了
数据安全存储是指将数据以安全的方式存储在存储系统中,以确保数据的机密性、完整性和可用性。要控制数据安全存储的权限以保障安全,可以采取以下措施: 访问控制列表(ACLs):使用ACLs来定义对存储数据的访问权…...

麒麟系统mate_indicators进程占用内存资源高
一、问题现象 故障现象:环境出现内存溢出 操作系统:KYlin10-SP2 二、问题定位 发现mate-indicators进程占用内存资源达到节点总内存40%,导致服务出现内存熔断 临时解决 systemctl restart lightdm.service systemctl set-default multi-u…...

Docker高级篇之轻量化可视化工具Portainer
文章目录 1. 简介2. Portainer安装 1. 简介 Portianer是一款轻量级的应用,它提供了图形化界面,用于方便管理Docker环境,包括单机环境和集成环境。 2. Portainer安装 官网:https://www.portainer.io 这里我们使用docker命令安装&…...

Vue32-挂载流程
一、init阶段 生命周期本质是函数。 1-1、beforeCreate函数 注意: 此时vue没有_data,即:data中的数据没有收到。 1-2、create函数 二、生成虚拟DOM阶段 注意: 因为没有template选项,所以,整个div root都…...

算法金 | 一个强大的算法模型:t-SNE !!
大侠幸会,在下全网同名「算法金」 0 基础转 AI 上岸,多个算法赛 Top 「日更万日,让更多人享受智能乐趣」 t-SNE(t-Distributed Stochastic Neighbor Embedding)是一种用于降维和数据可视化的非线性算法。它被广泛应用于…...

用IAST工具强化“越权检测”能力,提升系统安全性
什么是越权漏洞 越权漏洞是一种常见的逻辑安全漏洞。越权漏洞指的是攻击者利用系统中的漏洞,获得超过其正常权限的访问权限,执行未授权操作。 越权漏洞主要分为两种类型:水平越权(横向越权)和垂直越权(纵…...

VirtualStudio配置QT开发环境
环境 VirtualStudio2022Qt5.12.10 安装msvc工具链(这一步不是必须的) 打开virtual studio,打开Virtual Studio Installer界面选择要安装的msvc版本,点击安装 安装VirtualStudio扩展 在线安装 打开virtual Studio,…...

Nature发文介绍使用ChatGPT帮助学术写作的三种方式
文章链接:https://www.nature.com/articles/d41586-024-01042-3 一、介绍 这篇文章是由Dritjon Gruda撰写的,讨论了生成性人工智能(AI)在学术写作、编辑和同行评审中的三种应用方式。Gruda认为,尽管学术界对聊天机器…...

【网络安全的神秘世界】Kali 自带 Burp Suite 使用指南:字体与CA证书设置详解等
🌝博客主页:泥菩萨 💖专栏:Linux探索之旅 | 网络安全的神秘世界 | 专接本 | 每天学会一个渗透测试工具 Kali 自带 Burp Suite 使用指南目录 Burp Suite的打开方式设置Burp Suite软件的字体大小查看Burp Suite 默认代理在火狐浏览器…...

IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...

python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...

短视频矩阵系统文案创作功能开发实践,定制化开发
在短视频行业迅猛发展的当下,企业和个人创作者为了扩大影响力、提升传播效果,纷纷采用短视频矩阵运营策略,同时管理多个平台、多个账号的内容发布。然而,频繁的文案创作需求让运营者疲于应对,如何高效产出高质量文案成…...
Go 语言并发编程基础:无缓冲与有缓冲通道
在上一章节中,我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道,它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好࿰…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...

Linux 中如何提取压缩文件 ?
Linux 是一种流行的开源操作系统,它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间,使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的,要在 …...
Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换
目录 关键点 技术实现1 技术实现2 摘要: 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式(自动驾驶、人工驾驶、远程驾驶、主动安全),并通过实时消息推送更新车…...

逻辑回归暴力训练预测金融欺诈
简述 「使用逻辑回归暴力预测金融欺诈,并不断增加特征维度持续测试」的做法,体现了一种逐步建模与迭代验证的实验思路,在金融欺诈检测中非常有价值,本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...