深入理解C++系列 || NO1.引用()
今天在此开启一个新的系列:深入理解C.也开始我的学习之路,主要面向初学者和复习相关的知识.由于C语言和C有相当部分的知识重叠,故在此主要更新他们不同的和C独特内容部分的知识.持续更新,欢迎大家点赞关注.前言在 C 中引用Reference是一个非常核心且实用的特性它为我们提供了一种更安全、更简洁的方式来操作变量。很多初学者会把它和指针搞混其实两者有着本质的区别。今天我们就从基础概念讲起一步步深入理解引用的方方面面。1.什么是引用?1.1 核心定义形象来说,引用就是变量的 “别名”就像一个人可以有大名和小名不管叫哪个指的都是同一个人。int a 10; int b a; // 定义引用b 是 a 的别名核心注意:(1).b和a指向同一块内存地址.(即a和b本身就是一个东西)(2). 修改b等价于修改a.(3). 引用必须在定义时初始化不能 “空引用”(必须初始化已有变量).1.2 从内存角度理解我们可以通过打印出a和b的地址来验证:#include iostream using namespace std; int main() { int a 10; int b a; cout a 的地址 a endl; cout b 的地址 b endl; cout a 的值 a endl; cout b 的值 b endl; b 20; // 修改 b cout 修改后 a 的值 a endl; return 0; }运行结果:从结果中可以看出,变量a和引用b的地址完全相同(即它们本身其实是一种东西),修改其中一个,那么另一个当然也会跟着变化.1.3 个人理解:可能还有很多人对于变量a和引用b本身是一个东西有些不太理解.但如果屏幕前的你学过C语言中的#define 宏定义,那么就应该很容易理解的效果了.它们非常相像:纯粹是别名没有实体不占独立空间宏定义:#define b a你写b编译器直接把它替换成 a.引用:int a 10; int b a;你写b编译器也直接把它当成 a.最终总结:内存里只有一块空间名字叫a,而b不是新变量没有自己的盒子。引用就是变量的别名和宏定义一样只是换个名字不是新东西。a 和 b 就是同一个东西不是两个东西指向同一个地方2. 引用的核心规则(重要)2.1 引用必须初始化引用在定义时必须绑定一个已存在的变量不能定义 “空引用”int b; // ❌ 错误未初始化 int a 10; int b a; // ✅ 正确绑定变量 a2.2 一旦绑定终身不变引用绑定一个变量后就不能再绑定其他变量了int a 10, c 20; int b a; b c; // ❌ 不是改绑而是把 c 的值赋给 a此时 a 变成 202.3. 不能绑定常量除非是 const 引用前面看到的都是引用初始化是绑定一个变量,原来是一般不能直接绑定常量int ref 10; // ❌ 错误不能绑定字面量常量 const int ref 10; // ✅ 正确const 引用可以绑定常量const引用会为临时常量创建一个临时变量然后绑定到这个临时变量上。3. 引用的常用应用场景3.1 函数传参(最常用)在将引用传参前我们先复习下之前在C语言中学过的的传值调用和传址调用.3.1.1传值调用函数会创建变量的副本修改副本不会影响原变量.通俗来说:实参调用函数时括号里真实传进去的值 / 变量形参函数定义时括号里写的接收参数只是个 “占位名字”.也就是: 形参是实参的一份拷贝,在某函数中修改了形参并不会影响实参的值.void func(int x) { x 100; // 修改的是副本 } int main() { int a 10; func(a); cout a; // 输出 10原变量未被修改 return 0; }3.1.2 传址调用(指针)使用指针变量,向函数传入实参变量的地址,这样在函数中通过解引用改变变量的值,也就是直接改变了这个地址所存储变量的值.指针和引用在一定程度上有点混淆,我们会在最后做个比较.void func(int* x) //传入实参的地址 { *x 100; //直接修改地址内的值 } int main(void) { int a 10; func(a); cout a endl; //输出的是100 return 0; }3.1.3 引用传递函数直接操作原变量无需拷贝效率更高.void func(int x) { x 100; // 直接修改原变量 } int main() { int a 10; func(a); cout a; // 输出 100原变量被修改 return 0; }相信不用我强调大家都会自己记起了,变量和引用本质上就是一个东西,故传入a的引用就等于传入了a本身而不是实参a的拷贝(效果上与指针相同).3.2 传递大对象时避免拷贝对于大型对象如结构体、类对象值传递会拷贝整个对象,因为占用内存较大所以效率极低引用传递(直接传入大型对象本身,不需要拷贝)就可以避免这个问题:struct Student { char name[100]; int age; float score; }; // 值传递拷贝整个 Student 对象效率低 void printStudent(Student s) { cout s.name endl; } // 引用传递直接操作原对象无需拷贝 void printStudent(const Student s) { cout s.name endl; }注: 大家都知道const修饰的变量不可以被修改,这里使用const引用既避免了拷贝又保证了数据不会在函数中被意外修改。3.3 函数返回引用函数可以返回引用但要注意不能返回局部变量的引用// 正确返回静态变量的引用 int getStaticVar() { static int x 10; return x; } // 错误返回局部变量的引用局部变量在函数结束后会被销毁 int getLocalVar() { int x 10; return x; // ❌ 危险返回了无效内存的引用 } int main() { int ref getStaticVar(); cout ref endl; // 输出 10 ref 20; cout getStaticVar() endl; // 输出 20 return 0; }根据局部变量的特性,在该变量离开它的作用域后就会自动销毁,也就是函数中的局部变量不能离开函数体.那返回它的引用就毫无意义了,因为函数结束后这个局部变量的空间就已经被销毁了.3.4 引用作为循环变量遍历容器在遍历容器时使用引用可以避免拷贝元素同时可以修改元素#include vector using namespace std; int main() { vectorint vec {1, 2, 3, 4, 5}; // 普通遍历拷贝每个元素 for (int x : vec) { x * 2; // 修改的是副本不会影响 vec } // 引用遍历直接操作原元素 for (int x : vec) { x * 2; // 修改 vec 中的元素 } // const 引用遍历只读避免拷贝 for (const int x : vec) { cout x ; } return 0; }vector相关知识,我们以后再慢慢介绍.这里大家先了解下.3.5 数组的引用可以定义数组的引用语法如下:int arr[5] {1, 2, 3, 4, 5}; int (ref)[5] arr; // ref 是数组 arr 的引用 ref[0] 10; // 修改 arr[0] 的值4. 常引用(const)详解4.1 定义与作用常引用就是用const修饰的引用它禁止通过引用修改原变量int a 10; const int b a; b 20; // ❌ 错误不能通过 const 引用修改变量 a 20; // ✅ 正确可以直接修改原变量4.2 常引用的特殊特性(1). 可以绑定常量、临时变量const int ref 10; // ✅ 绑定字面量常量 const int ref a 5; // ✅ 绑定表达式的临时结果(2). 可以绑定不同类型的变量会进行类型转换double d 3.14; const int ref d; // ✅ 先把 d 转为 int再绑定到临时变量5. 引用 VS 指针 :联系与区别很多初学者容易混淆引用和指针这里用表格清晰对比两者的区别特性引用指针*定义方式int ref a;int *p a;是否必须初始化必须可以不初始化可以为 nullptr是否可以改绑不可以可以指向其他变量是否可以为 “空”不可以可以为 nullptr操作方式直接使用变量名需要解引用*p安全性更安全无野引用容易出现野指针、空指针问题内存占用不占用额外内存别名占用 4/8 字节存储地址1. 指针可以实现引用的功能但引用更安全// 指针实现类似引用的效果 int a 10; int *p a; *p 20; // 修改 a 的值 // 引用实现 int ref a; ref 20; // 修改 a 的值指针需要手动管理地址和解引用而引用自动处理这些代码更简洁安全。2. 指针的灵活性是引用无法替代的指针可以指向数组的不同元素int arr[] {1, 2, 3, 4, 5}; int *p arr; p; // 指向 arr[1]指针可以动态分配内存int *p new int(10);6. 总结引用是 C 中非常实用的特性它的核心优势在于简洁安全无需手动管理地址和解引用避免了指针的很多问题效率高效传递大对象时无需拷贝性能接近指针可读性好代码更直观不容易出错引用最常用的场景是函数传参和遍历容器尤其是const引用既能保证效率又能保证数据安全。在此不胜感谢能够看到这里的同学,如果发现文章有错误还请不吝赐教.后续内容会不断更新,感兴趣的同学可以关注点赞收藏慢慢观看.万分感谢!-------------------------------------------------------------------------------------------完2026.5.11---14:02