Skip to content

指针 / 引用 / 悬空 / 野 / 常量指针

一、指针 vs 引用的区别(高频)

维度指针引用
可变绑定可重新指向别处 ✅一旦绑定不可改
是否占内存占有(存地址)别名本质,物理上可不占位(编译器优化) 实现层面通常也占一个 slot
可否为空可(nullptr/未初始化野指针)必须绑定有效对象,无空引用
多级int**不可(无引用的引用)
语义值=地址,需解引用 *p直接当成别名用 r
安全性需判空、易悬空更安全(无天然空、生命周期经编译器追踪难悬空)
重载支持引用重载,引用于左值可区分

记法:引用是「已有对象的别名/变量别名」,不 new 不 delete;指针是「存地址的变量」。

传参建议:想在函数内改实参/避免拷贝 → 尽量用引用const T& 只读);需要可空 / 指向数组循环 / 表示"无值"或所有权 → 用指针。提供 "& 给左值传参可同时保留修改 + 避免拷贝" 的体感答题。

二、悬空指针 vs 野指针

类型定义成因结果
悬空指针指向已被释放对象delete 后没置空、返回局部地址、容器扩容后引用等解引用=UB(可能仍是旧值/崩)
野指针指向随机未知地址未初始化指针解引用=UB(Segfault 常见)

避免/修复

  • 指针必须初始化T* p = nullptr)。
  • delete立即置空delete p; p = nullptr;)仍有人误用 null 不崩。
  • 优先智能指针杜绝手动 delete。
  • 不返回局部对象地址(返回引用给调用方长期用)——局部变量离开函数帧即失效。

三、常量指针 vs 指针常量(必考混淆题)

口诀:const* 的相对位置——* 左边修饰"指向的对象",* 右边修饰"指针本身"

1. 常量指针(pointer to const,指向常量,const 在 * 左)

cpp
const int* p;    // p 指向的对象是 const:不能 *p=…
int const* p2;   // 等价
  • 可修改 p 本身(改指向),不能通过 *p 改对象值

2. 指针常量(const pointer,指针本身是常量,const 在 * 右)

cpp
int* const p;    // p 本身 const:不能改 p 指向
  • *p = … 改对象值,不能改 p 本身

3. 都常量

cpp
const int* const p;  // 既不能改指向,也不能改对象值

记忆

写一行代码最清楚:

cpp
int x=1,y=2;
const int* a = &x;  a = &y;   // ✅ 可改指向   *a=…  ❌
int* const b = &x;  *b = 3;   // ✅ 可改值      b=&y  ❌

四、指针的有趣题

Q1. 空指针/函数指针/成员函数指针

  • nullptr(C++11)类型 std::nullptr_t,可转任何指针类型;比 NULL(宏=0)类型安全、不可与整数混淆。
  • 函数指针:int(*fp)(int,int)=add; 调用 fp(1,2)
  • 成员函数指针:int(A::*fp)()=&A::add; 需用 (a.*fp)() 调用,与对象绑定。

Q2. 指针大小

64 位下指针恒 8 字节(不管指向 int/double/自定义),且不同指针类型都 8。空指针/指向栈/堆地址的指针都是 8。

Q3. 为什么用 void* 不能直接加减?

void 大小不确定(不能求 sizeof(void)),标准不允许 void* 算术,需先转 char*/unsigned char* 再按字节。

Q4. this 指针

  • 指向「当前对象」的指针(类型 T* const,不可改 this 本身,可解引用)。
  • const 成员函数里的 this 是 const T*,不能借此改对象非 mutable 成员。
  • this 在编译期是隐式第一参数(成员函数实现为带 this 的普通函数:func(T* this, 参数…))。

Q5. 引用与指针底层

引用实现通常就是一个指针(存地址),所以 sizeof(引用变量)=指向类型大小,占用与指针相同 slot。但语义上不是对象,不产生独立赋值/复制为地址的行为(拷贝引用即拷贝对象,除非是 const 引用到临时等)。

C++ 面试八股 · VitePress 版