C++引用概念及用法全解
一、什么是引用引用是C中的一种语法特性可以理解为变量的别名。引用本身不占用独立的内存空间它和被引用的变量共享同一块内存。引用的基本用法123456789101112intmain() {inta 10;int ra a;// ra是a的别名a 10;cout ra endl;// 输出20ra 10;cout a endl;// 输出30return0;}关键点对引用的操作就是对原变量的操作两者完全等价。二、引用的三大特点1. 定义引用时必须初始化12int ra;// ❌ 错误引用必须初始化int ra a;// ✅ 正确原因引用是变量的别名别名必须依附于某个已存在的变量不能独立存在。2. 不存在空引用12int ra NULL;// ❌ 错误不能给引用赋空值int* p NULL;// ✅ 指针可以为空原因引用必须绑定到一个有效的变量不能指向空地址。指针是独立的变量可以存储空地址但引用不是变量它只是别名。3. 引用一旦绑定不能改变指向123inta 10, b 20;int ra a;ra b;// 这不是让ra指向b而是把b的值赋给a即a 20原因引用在初始化时绑定了目标变量之后所有对引用的操作都直接作用于该变量无法重新绑定到其他变量。对比指针1234inta 10, b 20;int* p a;// 指针可以改变指向p b;// 现在p指向b*p 100;// 修改b的值为100三、引用作为函数参数引用的本质引用是变量的别名不是副本。对引用的操作就是对原变量的操作。基于这个特性引用最常用的场景是作为函数参数主要解决两个问题1. 在函数内部修改外部变量C语言中函数参数默认是传值形参是实参的副本函数内部修改形参外面的实参不受影响。123456789101112// C语言传值交换失败voidSwap(inta,intb) {inttmp a;a b;b tmp;}intmain() {intx 10, y 20;Swap(x, y);// x和y还是10和20没变}想要修改实参必须传指针123456// C语言传指针交换成功voidSwap(int* a,int* b) {inttmp *a;*a *b;*b tmp;}C的引用可以做到同样的事语法更简洁123456789101112// C传引用交换成功voidSwap(int a,int b) {inttmp a;a b;b tmp;}intmain() {intx 10, y 20;Swap(x, y);// 调用时和传值一样但实参被改了cout x y endl;// 输出20 10}优点调用时不用取地址函数内部不用解引用代码更清晰。2. 避免拷贝提高效率当参数是大型对象如结构体、类时传值会拷贝整个对象开销很大。传引用只传递地址4/8字节效率更高。12345// 传值拷贝整个Student对象几十字节voidPrintStudent(Student s) { ... }// 传引用只传递地址4/8字节不拷贝voidPrintStudent(constStudent s) { ... }注意对于int、char这类小型数据传值反而更快因为直接复制到寄存器不需要间接访问。所以小型数据用传值大型对象用const引用。3. 三种参数传递方式对比方式本质能否修改实参效率小型数据效率大型对象传值副本❌ 不能高低传指针地址✅ 能中高传引用别名✅ 能中高四、普通引用 vs const引用1. 普通引用可读可写1234inta 10;int ra a;// 普通引用ra 100;// ✅ 可以修改cout ra;// ✅ 可以读取2. const引用只读1234inta 10;constint cra a;// 常引用只读cout cra;// ✅ 可以读取cra 100;// ❌ 错误不能通过常引用修改3. 权限规则看原变量的权限引用的权限不能超过原变量。原变量是普通变量可读可写→ 引用可以是普通引用也可以是常引用原变量是常量只读→ 引用只能是常引用12345678inta 10;// 普通变量可读可写constintb 20;// 常量只读int ra a;// ✅ 普通引用引用普通变量constint cra a;// ✅ 常引用引用普通变量int rb b;// ❌ 错误普通引用不能引用常量权限超了constint crb b;// ✅ 常引用引用常量一句话变量是什么权限引用就不能超过这个权限。五、const引用的万能特性const引用可以引用任何东西普通变量、常变量、字面常量甚至临时对象。1. 引用普通变量12inta 10;constint cra a;// ✅2. 引用常变量12constintb 20;constint crb b;// ✅3. 引用字面常量1constint crx 30;// ✅ 可以背后原理当const引用绑定到字面常量时编译器会生成一个临时变量来保存这个常量然后让引用指向这个临时变量。123// 编译器实际做的事inttmp 30;constint crx tmp;注意引用本身不占内存但被引用的对象临时变量需要占内存。这个临时变量由编译器自动创建和管理它的生命周期和引用一致。4. 引用表达式结果12inta 10, b 20;constint cr a b;// ✅ 表达式结果是临时变量const引用可以绑定六、引用的常见误区误区1引用可以重新绑定1234inta 10, b 20;int ra a;// ra是a的别名ra b;// ❌ 不是让ra指向b而是把b的值赋给aa变成20误区2引用占用空间引用本身不占用独立内存它只是原变量的别名。sizeof引用的结果是原变量的大小。123inta 10;int ra a;cout sizeof(ra);// 输出4int的大小不是指针的大小原因sizeof作用于引用时返回的是被引用对象的大小。误区3引用可以指向引用123inta 10;int ra a;int rra ra;// ❌ 错误不存在引用的引用原因引用是别名不是对象。不能给别名再起别名吗语法上不允许。七、不能返回局部变量的引用或地址先看一个错误示例123456789Student func() {Student sa{S001,Alice,F, 20 };returnsa;// 返回局部变量的引用}intmain() {Student p func();printf(%s, p.s_name);// 可能崩溃可能乱码可能碰巧正确}为什么错了困惑1返回地址本身有什么错返回地址本身没错。return sa返回的是一个数字内存地址这个操作是合法的。错的是函数结束后你还去用这个地址访问内存。困惑2为什么函数结束后就不能用了函数调用时系统会在栈上给局部变量分配空间。函数结束后这块空间被系统回收标记为“可重用”。但回收不是清零这块内存还在只是不再属于你了。下次调用其他函数时系统可能会把这块空间分配给别的变量里面的内容随时可能被覆盖。所以你去访问它结果是不可预测的。困惑3返回值和返回引用有什么区别1234567891011// 返回引用返回地址危险Student func1() {Student sa{ ... };returnsa;// 返回地址sa销毁后地址失效 ❌}// 返回值返回副本安全Student func2() {Student sa{ ... };returnsa;// 返回副本sa销毁不影响副本 ✅}区别返回引用把原件的地址告诉别人原件没了地址就成了空地址返回值复印一份交给别人原件没了复印件还在困惑4返回局部变量的地址和返回局部变量本身有什么区别看返回类型返回类型是Student或Student*返回的是地址危险返回类型是Student返回的是副本安全123Student func1() {returnsa; }// 返回类型是引用 → 地址Student* func2() {returnsa; }// 返回类型是指针 → 地址Student func3() {returnsa; }// 返回类型是对象 → 副本类比理解你在酒店开房sa就是你住的房间返回引用或地址你把房间号告诉别人退房函数结束房间被回收不再属于你别人拿着房间号回去找房间可能住了别人可能在打扫可能已经被改成仓库去用这个房间号 → 结果不可预测返回值你退房时把房间里的东西复印一份带走原来的房间怎么变都跟你无关。正确的做法1. 返回值拷贝1234Student func() {Student sa{ ... };returnsa;// 返回副本}2. 返回静态局部变量1234567Student func() {staticStudent sa{ ... };// 静态变量生命周期贯穿整个程序returnsa;}Student func() {staticStudent sa{ ... };// 静态变量生命周期贯穿整个程序returnsa;}3. 在堆上分配1234Student* func() {Student* p newStudent{ ... };// 堆上分配手动管理returnp;}一句话总结返回局部变量的地址本身没错错的是函数结束后你还去用这个地址。因为这块内存已经被系统回收不再属于你了。八、能不能定义引用数组结论不能定义“元素为引用的数组”但可以定义“数组的引用”。1. 不能定义元素为引用的数组1int rbr[5];// ❌ 错误不能定义引用数组原因数组是一段连续的内存空间每个元素都需要占用内存。引用本身不占内存它只是别名无法作为数组元素存在。2. 可以定义数组的引用12intar[5] {1,2,3,4,5};int(rar)[5] ar;// ✅ 正确rar是数组ar的引用含义rar是整个数组ar的别名不是元素为引用的数组。3. 对比写法含义是否正确int rbr[5]元素为引用的数组❌ 错误int(rar)[5]数组的引用✅ 正确记忆技巧括号位置决定一切。靠近数组名表示引用整个数组靠近类型表示元素是引用。九、数组名退化问题1. 数组名退化的规则数组名在三种情况下不会退化保持为整个数组sizeof(ar)ar取数组地址引用数组int(rar)[n] ar其他情况数组名退化为数组首元素的地址。1234567intar[5] {1,2,3,4,5};cout sizeof(ar);// 205*4未退化int(*p)[5] ar;// 取数组地址未退化int(rar)[5] ar;// 引用数组未退化int* q ar;// 退化ar变成int*2. 数组名作为函数参数退化问题C中数组名作为参数传递给函数时会退化为指针丢失数组大小信息。1234voidfuna(intbr[5]) {cout sizeof(br);// 输出8指针大小不是20// 函数内部不知道数组有多大只能通过额外参数传入长度}如果希望函数内部能知道数组的大小可以用数组的引用作为参数1234voidfunb(int(rar)[5]) {cout sizeof(rar);// 输出20保留了数组大小// 函数内部可以直接用sizeof获取数组长度}关键点用数组的引用作为参数可以保留数组的大小信息避免退化。十、引用与指针的区别1. 语法规则上的区别对比项引用指针本质变量的别名存储变量的地址内存分配不分配独立内存分配4/8字节内存使用方式直接使用需要解引用*能否改变指向不能能必须初始化是否是否可为空不能可以NULL/nullptrsizeof结果原变量的大小指针本身的大小4/8多级无无引用的引用有二级、n级指针操作改变原变量的值改变指向的地址1234567// 演示操作的区别intar[5] {10,20,30,40,50};int ra ar[0];int* p ar[0];ra;// ar[0]变成11p;// p指向ar[1]2. 汇编层面的本质从汇编角度看指针和引用没有区别都是地址。1234inta 10;int ra a;int* p a;// 底层实现ra和p都是存储a的地址引用在底层也是用指针实现的只是编译器做了语法糖让使用更方便、更安全。3. 一句话总结维度引用指针语法层面别名更安全地址更灵活汇编层面都是地址都是地址使用建议能用引用就用引用需要改变指向或可为空时再用指针。总结知识点核心要点引用本质变量的别名不占独立内存三大特点必须初始化、不能为空、不能改指向const引用只读可引用普通变量/常变量/字面常量权限规则引用权限不能超过原变量const引用万能可绑定字面常量和临时对象编译器自动生成临时变量引用作为参数可修改外部变量、避免大对象拷贝返回局部变量不能返回局部变量的引用或地址函数结束后内存被回收数组的引用可定义数组引用int(rar)[5]不能定义引用数组int rbr[5]数组名退化sizeof//数组引用 三种情况不退化函数参数会退化引用 vs 指针引用更安全不能为空、不能改指向指针更灵活到此这篇关于C引用全解的文章就介绍到这了

相关新闻

Navicat无限试用终极指南:免费开源脚本,三步告别 14 天倒计时

Navicat无限试用终极指南:免费开源脚本,三步告别 14 天倒计时

Navicat无限试用终极指南:免费开源脚本,三步告别 14 天倒计时 【免费下载链接】navicat_reset_mac navicat mac版无限重置试用期脚本 Navicat Mac Version Unlimited Trial Reset Script 项目地址: https://gitcode.com/gh_mirrors/na/navicat_reset_m…

2026/10/16 11:59:03 阅读更多 →
Docker Desktop 安装配置教程(Windows + Mac,走通第一个容器)

Docker Desktop 安装配置教程(Windows + Mac,走通第一个容器)

Docker 是什么 Docker 能让你把一个应用和它依赖的所有东西打包成一个"盒子",这个盒子在哪台机器上都能原样跑起来,不用再纠结"我电脑能跑你电脑怎么报错"这种问题。装 Docker 就是给自己省配置环境的时间。 Windows 安装前检查 在装…

2026/10/19 19:08:03 阅读更多 →
数据域:数据仓库的骨架设计,从业务梳理到模型落地的实战指南

数据域:数据仓库的骨架设计,从业务梳理到模型落地的实战指南

1. 数据域:一个被误解的“简单”概念如果你在数据仓库、数据治理或者数据分析的圈子里待过一阵子,大概率听过“数据域”这个词。听起来挺高大上的,对吧?但每次开会,当有人问“这个指标到底该归到哪个数据域&#xff1f…

2026/10/17 18:00:51 阅读更多 →

最新新闻

MATLAB小波分析实战手册:EEG/ECG/振动信号降噪与特征提取

MATLAB小波分析实战手册:EEG/ECG/振动信号降噪与特征提取

简介:本资源是《MATLAB小波分析超级学习手册》配套的完整程序代码包,面向信号处理、图像分析及科研工程领域的MATLAB初学者与进阶用户,聚焦小波理论落地与工程实践能力提升。压缩包含119个文件(113个.m函数脚本、4个.wav测试音频、…

2026/10/20 12:23:13 阅读更多 →
华为交换机LACP链路聚合配置实战:负载分担与故障排查

华为交换机LACP链路聚合配置实战:负载分担与故障排查

1. 从一个真实故障说起:为什么单根网线永远不够用很多刚入行的网络运维同行都有过这样的经历:机房搬迁,核心交换机到接入交换机的链路只有一根千兆网线,业务高峰期一到,监控大屏上那条链路的使用率直接顶到95%以上&…

2026/10/20 12:23:13 阅读更多 →
数据预处理全攻略:从数据清洗到缺失值处理,打好数据分析地基

数据预处理全攻略:从数据清洗到缺失值处理,打好数据分析地基

做数据分析这几年,我见过太多人把精力全扑在算法调参上,反复调了好几天,模型效果怎么都上不去,最后排查来排查去才发现,问题根本不在模型,而是喂给模型的数据本身就没洗干净。脏数据、缺失值、量纲悬殊、时…

2026/10/20 12:23:13 阅读更多 →
用 LangGraph 搭建带工具调用的多轮智能体:从状态机设计到流式输出实战

用 LangGraph 搭建带工具调用的多轮智能体:从状态机设计到流式输出实战

引言:能调工具的 Chatbot,离"可用"还有多远 过去一年,几乎每个团队都写过类似这样的代码:把工具 schema 丢给 LLM,拿回 tool_calls,for 循环里逐个执行,把结果拼回消息列表&#xff0…

2026/10/20 12:23:13 阅读更多 →
用 LangChain 和 Ollama 搭建本地 RAG 智能体问答系统

用 LangChain 和 Ollama 搭建本地 RAG 智能体问答系统

引言:本地 RAG 的真实驱动力 过去一年,我参与过几个企业内部知识库项目,几乎每一次技术选型会议都会出现同一个分歧:用云端大模型 API,还是全部本地化部署? 云端方案的优势很明确——模型能力强、开箱即用。…

2026/10/20 12:23:13 阅读更多 →
STM32F4实战:EC20 TCP透传模式与AT指令初始化流程详解

STM32F4实战:EC20 TCP透传模式与AT指令初始化流程详解

简介:针对EC20模块在STM32F4系列微控制器上实现TCP透传通信的场景,这份压缩包提供了一套完整的Keil工程源码,适合物联网开发者、嵌入式工程师以及学习STM32通信技术的读者参考。压缩包内共有174个文件,整体大小约4.06MB&#xff0…

2026/10/20 12:22:13 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 10:02:08 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:45 阅读更多 →