C语言进阶:void指针、二级指针、指针数组与数组指针、二维数组传参全解
前言
今天系统学习C语言高阶指针知识点,涵盖万能void指针、二级指针、const修饰指针、指针数组与数组指针区分、二维数组指针底层逻辑与函数传参,这部分是C语言笔试、开发核心难点,整理完整知识点、易错点与实操逻辑,方便复习查阅。
一、void万能指针
1. 核心概念
void指针是无固定类型的通用指针,可以接收任意数据类型变量的内存地址,作为通用地址容器。
64位系统所有指针均占8字节,void指针也不例外,但编译器不知道它指向的数据占多少字节,因此禁止直接解引用*。
2. 转换规则
- 任意类型
int* / char* / float*可以隐式自动转为void*; - 使用void指针取值、运算时,必须强制转换为原数据类型指针。
3. 实操示例
直接操作指定物理内存地址赋值:
// 将0x12345678地址强制转为int*,赋值0x11223344*((int*)((void*)0x12345678))=0x11223344;4. 典型用途
- 封装通用工具函数,兼容多种数据类型入参;
- 内存操作函数
memcpy/memset底层全部使用void*实现通用逻辑。
二、二级指针 int** 详解
1. 定义与含义
普通变量int a→ 一级指针int* p = &a(存变量地址)
一级指针int* p→ 二级指针int** q = &p(存一级指针变量的地址)
多层取值关系:
q:一级指针变量p的地址*q:等价p,普通变量a的地址**q:等价*p,变量a存储的真实数值
2. 唯一核心使用场景
当我们需要在函数内部修改函数外部定义的一级指针变量时,必须传递二级指针。
普通值传递、一级地址传递只能修改原变量内容,无法修改指针本身的指向。
3. 适用拓展
字符串指针数组做函数参数时,必须搭配二级指针接收。
三、const修饰指针四种写法(必背)
const关键字代表只读,修饰指针时分两种修饰对象:修饰指针指向的数据、修饰指针变量本身。
const int *p/int const *p
const修饰*p,指针p可以修改指向,但不能通过p修改指向空间的值;int *const p
const修饰指针p本身,定义时必须初始化,p的指向永久不能修改,但可修改*p;const int *const p
双重限制:指针不可改指向,指向内容也不可修改,完全只读。
四、指针数组 VS 数组指针(面试高频区分点)
1. 指针数组int *a[5]
- 本质:数组,数组内每一个元素都是
int*一级指针; - 内存大小:64位系统 5 * 8 = 40字节;
- 核心用途:存储一组字符串,替代笨重的二维字符数组;
- 示例:
constchar*month[]={"January","February","March"};2. 数组指针int (*p)[5]
- 本质:指针,仅占8字节;专门指向包含5个int的完整一维数组;
- 运算特性:
p++一次性跳过5个int(20字节),步长为整个数组大小; - 区分技巧:运算符优先级
[] > *,不加括号是数组,括号包裹(*p)才是指针。
五、二维数组底层与指针访问
1. 二维数组存储规则
int a[2][3]在内存中逐行连续存储,不存在行间空隙。
2. 各地址层级含义
a:数组指针,指向第0整行,类型int(*)[3],a++跳过一整行3个int;a[0]/*a:普通int*指针,指向第0行第0个元素;&a[0][0]:第一个元素的原始地址。
3. 元素等价访问方式(5种完全等效)
// 访问第m行第n列a[m][n]*(a[m]+n)*(*(a+m)+n)*(p+m*3+n)// p为int*类型*(*(q+m)+n)// q为数组指针int(*)[3]六、二维数组函数传参标准写法
- 硬性规则:形参必须声明列的固定长度,行数可省略;
- 底层接收依赖数组指针类型:
// 两种等价标准写法intgetMax(int(*arr)[3],introw);intgetMax(intarr[][3],introw);- 错误写法:
int fun(int arr[2][]),编译器无法计算行偏移,直接编译报错。
七、今日高频易错点汇总
- void指针直接
*解引用编译报错,缺少类型宽度,必须强制转换; - 分不清
int *a[5]与int (*a)[5],括号是区分数组/指针的关键; - const指针记忆混淆:
*左侧const限制内容,变量名前const限制指针指向; - 滥用二级指针:仅修改普通变量用一级指针,只有修改外部指针变量才用二级指针;
- 二维数组传参遗漏列数,导致编译失败;
- 数组指针运算步长理解错误,
int (*p)[5]自增一次跳过5个int; - 未初始化void指针、二级指针直接取值,触发程序段错误崩溃;
- 混淆一维数组
a(首元素指针)和&a(整个数组指针),二者步长天差地别。