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

指针不是“地址的别名”,而是类型化的地址值——它本身是变量,存储的是内存地址,且该地址必须能被解释为所声明类型的起始位置。
指针变量和普通变量在内存里没本质区别
所有变量(包括 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的地址,*pp是p(即&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 自动管理生命周期
真正难调试的,往往是“看似正常却偶然出错”的悬空指针——它可能在某次运行中恰好没触发段错误,但破坏了其他数据。









