指针和引用是语义、生命周期、底层行为完全不同的机制:引用是对象的别名,必须初始化且不可重绑;指针是存储地址的独立变量,可为空、可变、可算术运算。

指针和引用不是“差不多的两种写法”,而是语义、生命周期、底层行为完全不同的机制。选错一个,轻则编译不过,重则运行时崩溃或未定义行为。
引用必须绑定且不可重绑
声明时就得指向一个真实存在的对象,之后不能再换目标。这不是限制,而是设计契约:引用就是那个对象的另一个名字。
-
int x = 10; int& r = x;合法;int& r;编译直接报错error: declaration of reference variable 'r' requires an initializer -
r = y;不是让r指向y,而是把y的值赋给x(因为r就是x) - 函数返回局部变量的引用(如
int& f() { int x=0; return x; })会导致悬空引用,访问它就是未定义行为
指针可以为空、可变、可算术运算
指针是独立变量,有自己内存空间,存的是地址——这个地址可以是有效的,也可以是 nullptr,甚至可能是野地址。
-
int* p;合法但危险,此时p是未初始化的野指针;int* p = nullptr;明确为空,使用前必须判空 -
p = &x; p = &y;可以随时切换指向,这是实现链表、树等结构的基础 -
int arr[3] = {1,2,3}; int* p = arr; p++;合法,p现在指向arr[1];而int& r = arr[0]; r++;只改值,不能用++移动引用目标
sizeof 和底层实现差异直接影响性能判断
别被“引用是语法糖”误导——它不占额外空间,但 sizeof 结果反映的是被引用对象的大小,不是“引用本身”的大小(它没有“本身”)。
-
int x = 42; sizeof(x)是 4(或 8);sizeof(int&)也是 4(或 8),不是 0 -
sizeof(int*)在 64 位系统上固定为 8,不管它指向什么 - 引用参数传入函数时,编译器通常生成和指针一样的汇编指令(传地址),但你不用写
&或*;这省了语法噪音,但没省掉间接访问成本
函数参数和返回值场景下选哪个?看意图,不是看习惯
传参时用引用不是为了“避免拷贝”,而是为了表达“我操作的就是实参本体”;用指针则是为了表达“这个参数可能不存在,或者我需要重定向它”。
- 修改实参且不允许传空:用
int&(如void swap(int& a, int& b)) - 参数可选或需判空:必须用
int*(如void log(const char* msg),msg可为nullptr) - 返回局部对象?只能用指针(或智能指针),返回引用大概率悬空;返回大对象?优先考虑移动语义,而非硬套引用
最常被忽略的点:引用的绑定发生在初始化那一刻,之后任何赋值都是对原对象的修改;而指针的赋值是改变它自己存的地址。混淆这两者,代码逻辑就从“改数据”悄悄变成“改指向”,调试时很难察觉。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











