引用是变量的别名,必须初始化且不可重绑定;指针是存储地址的变量,可为空、可重赋值、支持算术运算;引用天生非空,指针需判空;引用传递避免拷贝并保证安全,指针更灵活但易出错。
引用和指针本质不同:引用是变量的别名,必须初始化且不能改绑;指针是存储地址的变量,可为空、可重赋值、可算术运算。
引用声明时必须绑定到有效对象,之后不能再指向其他对象:
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) { ... } },更灵活也更易出错引用传递主要用于避免拷贝、修改实参、实现操作符重载等场景。常见写法有三种:
void incr(int& x) {
++x; } —— 可修改原变量,适合“输出型”参数void print(const std::string& s) —— 避免大对象拷贝,且保证函数内不修改,接受字面量/临时对象void consume(std::string&& s) —— 绑定临时对象,支持移动语义,提升性能编译器通常将引用优化为直接访问原变量地址(无额外存储),而指针本身占内存(如8字节),并多一次解引用操作:
int& r = a; 在 watch 窗口里往往直接显示为 a 的值,和 a 完全同步int* p = &a; 会显示地址值,需手动展开 *p 才看到内容基本上就这些。理解差异关键不在“怎么写”,而在“它代表什么”——引用是别名,指针是地址。用对了,代码更安全;混用了,bug 往往悄无声息。