09 · 指针 ★核心中的核心
一句话理解:指针就是存「地址」的变量。 普通变量存数据,指针存数据在哪儿。
两个符号
int a = 10;
int *p = &a; // & 取地址:把 a 的地址存进 p
printf("%d\n", *p); // * 解引用:通过 p 拿到 a 的值 → 10
*p = 20; // 通过指针修改 a → a 变成 20
&:取地址运算符(&a= a 的地址)*:解引用运算符(*p= p 指向的那个值)- 声明时的
int *p里的*只是「表示 p 是指针」,别和解引用混淆。
内存图(务必脑中有图)
内存地址 变量
0x7ffd1000 a = 10 ← &a = 0x7ffd1000
0x7ffd1008 p = 0x7ffd1000 ← p 存的是 a 的地址
*p 顺着 p 里的地址找到 a
指针与数组的关系(必背)
int a[5] = {1,2,3,4,5};
int *p = a; // 数组名 = 首元素地址
p + 1; // 不是 +1 字节,而是 +1 个 int(步长 = sizeof(int) = 4)
*(a + i) == a[i]; // 完全等价
指针运算是按「类型大小」走的,int* 加 1 跳 4 字节,char* 加 1 跳 1 字节。
常见形态
| 写法 | 含义 |
|---|---|
int *p |
指向 int 的指针 |
int **p |
二级指针(指向指针的指针) |
void *p |
无类型指针,可指向任意类型(malloc 返回这个) |
NULL |
空指针,解引用会崩,用前必须判空 |
| 野指针 | 未初始化的指针,指向随机地址 → 解引用必崩 |
指针作为函数参数(最重要的用法)
void modify(int *x) { *x = 100; } // 想让函数改外部变量,就传指针
int v = 1;
modify(&v); // v 变成 100
安全铁律
- 指针必须初始化(
int *p = NULL;),否则是野指针。 - 解引用前判空:
if (p != NULL) { ... }。 free之后立刻把指针置NULL(防悬空指针,见 19-内存管理)。- 不要返回局部变量的地址(函数结束后栈内存失效)。
⚡ Java 对比
Java 没有指针,只有「对象引用」——引用是安全的、受 GC 管理的;C 的指针是裸露的地址,能指哪就指哪,也能指到不该指的地方然后崩溃。能力与风险同时放大。
关联
08-数组 · 10-函数指针与回调 · 11-字符串 · 19-内存管理 · 12-结构体