一、指针的本质回顾
指针是存储内存地址的变量,例如:
int a = 10;
int *p = &a; // p是一级指针,存储变量a的地址
此时:
`p`的值是变量`a`的地址(如`0x1000`)
`*p`通过地址访问`a`的值(`*p`即`a`的值10)
二、什么是多级指针?
多级指针是指向指针的指针,层级可以无限延伸(但实际开发中一般不超过三级)。
1. 二级指针
int **pp = &p; // pp是二级指针,存储指针p的地址
此时:
`pp`的值是`p`的地址(如`0x2000`)
`*pp`解引用得到`p`的值(即`a`的地址`0x1000`)
`**pp`解引用两次得到`a`的值(即10)
2. 三级指针
int ***ppp = &pp; // ppp是三级指针,存储pp的地址
`***ppp`最终访问到`a`的值
三、为什么需要多级指针?
1. 动态内存分配的典型场景
当需要在函数内部修改指针本身的值时,必须传递指针的指针(二级指针):
void allocate(int **arr) {
*arr = malloc(5 * sizeof(int)); // 修改外部指针的值
}
int main() {
int *my_array = NULL;
allocate(&my_array); // 传递指针的地址
// 现在my_array指向动态分配的内存
free(my_array);
return 0;
}
如果直接传递一级指针`int *arr`,函数内对`arr`的修改不会影响外部的`my_array`。
2. 处理多维数组
动态分配二维数组时,需要二级指针:
int **matrix;
matrix = malloc(3 * sizeof(int*)); // 分配行指针
for (int i = 0; i < 3; i++) {
matrix[i] = malloc(4 * sizeof(int)); // 为每行分配列
}
此时:
`matrix`是二级指针,指向一个指针数组
每个`matrix[i]`指向一维数组
释放内存时需要逆向操作:
for (int i = 0; i < 3; i++) {
free(matrix[i]); // 先释放每行
}
free(matrix); // 再释放行指针数组
四、多级指针的解引用规则
每一级`*`对应一层解引用:
int a = 10;
int *p = &a; // p → a
int **pp = &p; // pp → p → a
int ***ppp = &pp;// ppp → pp → p → a
printf("%d", **pp); // 输出10
printf("%p", *pp); // 输出p的值(即&a)
五、常见误区
1. 指针层级与数组维度
多级指针不等同于多维数组!例如:
`int arr`可以表示动态二维数组
`int arr[3][4]`是静态二维数组,内存连续
2. 内存管理风险
错误示例:
int **pp = malloc(sizeof(int*)); // 分配一个指针空间
*pp = 100; // 错误!未分配内存就赋值(野指针)
正确做法:
*pp = malloc(sizeof(int)); // 先为二级指针指向的一级指针分配内存
**pp = 100; // 现在安全了
六、总结核心
1. 多级指针的本质:指针的地址链式存储。
2. 核心用途:
动态内存分配(尤其是多维结构)
在函数中修改外部指针的值
3. 操作要点:
逐级解引用
内存分配/释放必须层级对应
4. 适用场景:当需要间接操作指针本身时(而不仅是操作指针指向的数据)。