2.1 指针与引用
指针和引用是 C++ 中比较基础但是也比较容易被混淆的一对概念。它们都能让我们"间接"地去操控一块内存中的数据,但是在语法约束和使用场景上有着本质区别。
语法层面的区别
从语法上看,指针和引用有三条最核心的差异。
第一是初始要求不同。指针可以不初始化(语法上可以,但是特别不建议哦,这是野指针呐!),也可以被赋值为 nullptr,表示不指向任何有效内存。但是引用不行,它在声明时候必须绑定到一个已经存在的变量身上。(注意哦,const 引用是个例外,它可以绑定到临时对象或字面量,如 const int& a = 10; 是合法的。)
第二点是,指针是一个独立的变量,可以重新指向其他地方(这个不必多说)。但是引用不行,它不能重新绑定到其他变量,如果后面再用赋值操作,也只会修改绑定对象的值。
第三是访问方式不同,指针需要解引用运算符 * 才能访问目标内存的值,但是引用就像是普通变量一样可以直接拿来用,这也是引用在代码可读性上的优势所在 —— 它隐藏了"地址"这一层抽象,让操作看起来就像在直接操作原变量,因而,引用也可以看成是变量的别名。
这三点可以用这个表简单概括:
| 指针 | 引用 |
|---|---|
可以为 nullptr | 必须初始化绑定到变量 |
| 可以重新指向其他内存 | 不可换绑 |
需要使用 * 解引用访问 | 可以直接访问 |
底层实现:引用是语法糖
尽管刚刚我们对比了半天它俩的差别,但是谁能想到从底层(汇编层面)看,它俩几乎没有区别!
这都是编译器的功劳:引用就是编译器实现的一种"语法糖",大多数的编译器在底层会为引用维护一个指针,通过这个指针来访问所绑定的对象。
引用的价值就是在指针的基础之上,屏蔽掉空指针、野指针、手动地址运算这类不安全操作,在保证地址传递能力的同时,提升代码安全性和可读性。
函数传参的三种方式
指针和引用对比的点大概也就以上这些,只讲这些有点干巴,也显得本篇内容有点少(作为 C++ 部分的第一篇这样不太好(◍•ᴗ•◍)ノ♡),那接下来顺便讲一下 C++ 函数传参的三种典型方式,这也是指针和引用比较常见的用途。
值传递是最朴素最常用的方式。就是把外部实参完整复制一份给内部形参,函数里面操作的是一个独立的临时副本,随便怎么折腾都不会影响外面的实参。这个方法逻辑直白,也不会改变原数据(如果你的函数目的就是改变原数据的话,那就算了嘿嘿)。但是如果我要处理一个超级超级大的数据,比如大数组,大自定义对象等,那拷贝起来太麻烦了,内存和时间损耗比较大,影响效率。
指针传递将变量的内存地址传入函数。函数通过解引用指针,可以直接修改外部原变量的值,同时避免了对象拷贝。但指针传递要求我们手动取地址,且函数内部需要处理指针可能为空的情况,语法上有点繁琐。
引用传递可以看作指针传递的"语法升级版"。它传递的是变量的别名,不发生拷贝,函数内部同样可以修改外部对象,但调用时无需取地址,函数内部也无需解引用,语法简洁自然。对于需要修改外部参数或避免大对象拷贝的场景,引用传递通常是首选。
来举个小例子看看:
#include <iostream>
using namespace std;
void test_1(int num)
{
num = 20; //只改变这个副本,主函数的num不受影响
cout<<"【test_1函数】num:"<<num<<endl;
}
void test_2(int* pointer)
{
*pointer = 30; //通过指针修改外层原始变量
cout<<"【test_2函数】*pointer:"<<*pointer<<endl;
}
void test_3(int& ref)
{
ref = 40; //直接修改原值
cout<<"【test_3函数】ref:"<<ref<<endl;
}
//主函数中的pointer、ref属于冗余写法,只是为了直观的演示,实际使用时直接传 &num、num 即可,不用额外创建变量;
int main()
{
int num = 10; //原变量
int* pointer = # //指向num的指针
int& ref = num; //绑定到num的引用
cout<<"【主函数】原num:"<<num<<endl<<endl;
test_1(num);
cout<<"【主函数】值传递后num:"<<num<<endl<<endl;
test_2(pointer);
cout<<"【主函数】指针传递后num:"<<num<<endl<<endl;
test_3(ref);
cout<<"【主函数】引用传递后num:"<<num<<endl;
return 0;
}代码就不再讲解啦,可以自己跑一下试试(其实结果也能直接"猜到"),本篇讲解就到这里啦~
本文内容主要来自个人学习与实践总结,受限于个人技术水平,难免存在理解不准确或表述疏漏等错误。 若您发现问题,或愿意就相关内容进一步交流,欢迎通过邮箱 571467648@qq.com 与我联系。感谢您的阅读与指正。