引用是变量的别名,必须初始化且不可重绑定;指针是存储地址的变量,可为空、可重赋值、支持算术运算;引用天生非空,指针需判空;引用传递避免拷贝并保证安全,指针更灵活但易出错。

引用和指针本质不同:引用是变量的别名,必须初始化且不能改绑;指针是存储地址的变量,可为空、可重赋值、可算术运算。
语法与初始化规则不同
引用声明时必须绑定到有效对象,之后不能再指向其他对象:
-
引用:
int a = 10; int& ref = a;—— ref 就是 a 的另一个名字,不能写int& ref;(不合法)或ref = b;(这是赋值,不是重绑定) -
指针:
int* ptr = &a;合法,也可先声明再赋值:int* ptr; ptr = &a;,还能中途改指向:ptr = &b;
空值与有效性检查
引用天生非空,语言层面禁止绑定到空值或临时对象(除非是 const 引用延长生命周期);指针可以为 nullptr,使用前通常需判空:
- 引用传参函数内无需检查有效性,但调用方必须确保传入的是合法对象
- 指针参数常写作
void func(int* p) { if (p != nullptr) { ... } },更灵活也更易出错
引用传递的实际用法
引用传递主要用于避免拷贝、修改实参、实现操作符重载等场景。常见写法有三种:
立即学习“C++免费学习笔记(深入)”;
-
非 const 引用:
void incr(int& x) { ++x; }—— 可修改原变量,适合“输出型”参数 -
const 引用:
void print(const std::string& s)—— 避免大对象拷贝,且保证函数内不修改,接受字面量/临时对象 -
右值引用(C++11起):
void consume(std::string&& s)—— 绑定临时对象,支持移动语义,提升性能
底层行为与调试表现
编译器通常将引用优化为直接访问原变量地址(无额外存储),而指针本身占内存(如8字节),并多一次解引用操作:
- 调试时,
int& r = a;在 watch 窗口里往往直接显示为a的值,和 a 完全同步 - 而
int* p = &a;会显示地址值,需手动展开*p才看到内容 - 汇编层面,引用常被内联消去,指针则保留明确的地址加载和间接寻址指令
基本上就这些。理解差异关键不在“怎么写”,而在“它代表什么”——引用是别名,指针是地址。用对了,代码更安全;混用了,bug 往往悄无声息。









