C++指针怎么理解_带你10分钟搞懂C++指针本质【精讲】

13次阅读

指针是存储内存地址的类型化变量,其值为另一变量地址,sizeof(int) 在 64 位系统中为 8 字节;p 按所声明类型读取地址处内容,& 和 * 是编译器的类型解释开关,不改变内存布局。

C++ 指针怎么理解_带你 10 分钟搞懂 C ++ 指针本质【精讲】

指针不是“地址的别名”,而是类型化的地址值——它本身是变量,存储的是内存地址,且该地址必须能被解释为所声明类型的起始位置。

指针变量和普通变量在内存里没本质区别

所有变量(包括 int*)都占一块内存,存着某个值。区别只在于:普通变量的值是数据(如 42),指针变量的值是另一个变量的地址(如 0x7fffa1234568)。你可以用 sizeof 验证:sizeof(int*) 在 64 位系统上通常是 8,和 sizeof(long) 一样,跟它指向什么类型无关。

  • 声明 int* p; 时,p 自己就占 8 字节,里面内容未初始化(垃圾值)
  • p = &x; 是把 x 的地址(一个纯数字)写进 p 这 8 字节里
  • *p 不是“取地址”,而是按 int 类型去读 p 所存地址处的 4 字节内容

&* 是编译器帮你看懂地址的“翻译开关”

&x 得到的是 x 的地址,类型是 int**p 是告诉编译器:“请把 p 里存的地址,当作 int 起始点去读”。这两个操作不改变内存布局,只影响类型检查和访问宽度。

  • 错误常见于:对字面量取地址,如 &42 → 编译报错:lvalue required as unary '&' operand
  • 危险操作:类型不匹配解引用,如 char c = 'a'; int* p = (int*)&c; printf("%d", *p); → 读了后面 3 字节垃圾,结果不可预测
  • int x = 10; int* p = &x; int** pp = &p;:这里 pp 存的是 p 的地址,*ppp(即 &x),**pp 才是 x

数组名不是指针,但多数场景下会“退化”为指针

int arr[5]; 中,arr 是数组类型(int[5]),有固定大小和内存布局;而 &arr 是指向整个数组的指针(类型 int(*)[5]),和 &arr[0](类型 int*)数值相同但类型不同。

立即学习 C++ 免费学习笔记(深入)”;

  • 传参时 void f(int a[]) 等价于 void f(int* a),数组名退化,长度信息丢失
  • sizeof(arr) 返回 20(5×4),sizeof(&arr) 返回 8,sizeof(&arr[0]) 也是 8 —— 说明 &arr&arr[0] 是两个不同类型的指针,只是碰巧指向同一地址
  • std::array<int></int>std::vector 可避免这种隐式退化带来的歧义

野指针、悬空指针、空指针的区别和应对

三者都导致 *p 行为未定义,但成因不同:

  • 野指针 :未初始化的指针,如 int* p; → 值随机,*p 访问非法内存 → 解决:声明即初始化,int* p = nullptr;
  • 悬空指针 :指向已释放 / 已销毁对象的指针,如 int* p = new int(5); delete p; cout → 内存可能已被重用或保护 → 解决:释放后立即置 <code>nullptr,或改用 std::unique_ptr
  • 空指针 :值为 nullptr(或 0),*p 必崩溃(多数平台)→ 安全:解引用前判空,但更推荐用 RAII 自动管理生命周期

真正难调试的,往往是“看似正常却偶然出错”的悬空指针——它可能在某次运行中恰好没触发段错误,但破坏了其他数据。

text=ZqhQzanResources