C语言深度解析:void指针、二级指针、指针数组与数组指针全梳理

发布时间:2026/8/4 4:22:28
C语言深度解析:void指针、二级指针、指针数组与数组指针全梳理 一、void * 万能空类型指针1. 核心概念普通指针int*/char*/float*都绑定了固定数据类型编译器会根据类型确定指针±1时偏移的字节数而void指针是无类型万能指针不绑定任何数据类型仅单纯存储内存地址不自带解析内存长度的规则。void*p;// 合法定义可存放任意类型变量的地址inta10;charchA;doubled3.14;pa;// int* 自动隐式转为 void*pch;// char* 自动隐式转为 void*pd;// double* 自动隐式转为 void*2. void指针的限制与强制转换规则void指针不能直接解引用*p、不能直接做自增自减运算编译器无法知道要读取几个字节的数据必须强制转换成对应类型指针后才能操作内存void*addr(void*)0x12345678;// 将0x12345678地址强制转为int*修改4字节内存值*((int*)addr)0x11223344;转换逻辑任意类型指针赋值给void*隐式自动转换无需强转void*赋值给具体类型指针必须显式强制类型转换否则编译报错。3. void指针典型应用场景通用函数参数实现接收任意类型数据的通用接口标准库memcpy/memset底层全用void*voidcopy_data(void*dest,void*src,intlen);泛型容器模拟C泛型一个指针数组存储不同类型数据地址底层内存操作直接操作物理/虚拟内存地址驱动、内核开发高频使用。二、二级指针**指针的指针1. 基础原理普通指针int *p存放普通变量地址二级指针int **q存放一级指针变量的地址相当于指针变量的容器。内存层级关系普通变量a←一级指针pa←二级指针qpinta100;int*pa;// p存a的地址int**qp;// q存一级指针p的地址// 取值分层解析printf(a的值%d\n,a);printf(一级指针p指向的值%d\n,*p);printf(二级指针q解一层p的地址 %p\n,*q);printf(二级指针q解两层a的值 %d\n,**q);2. 二级指针核心作用函数内修改外部一级指针的指向值传递仅拷贝数值无法修改外部实参若函数需要修改外部指针变量本身必须传入该指针的地址二级指针。存储字符串数组指针数组传参存储多个字符串的char *str_arr[]本质是一级指针数组数组名作为函数参数会退化为二级指针char **。三、指针数组 vs 数组指针极易混淆核心考点3.1 指针数组数组元素全是指针语法数据类型 *数组名[长度][]优先级高于*先结合数组再修饰指针。int*a[5];含义定义数组a共5个元素每个元素类型是int *int型一级指针64位系统下每个指针占8字节整个数组总大小5*840字节。典型使用场景存储字符串数组C语言批量存储多段字符串优先使用字符指针数组比二维字符数组更省内存// 每个字符串单独存常量区数组仅存字符串首地址char*month[]{Jan,Feb,Mar,Apr,May};printf(%s,month[0]);// 打印Jan3.2 数组指针指针专门指向一整个数组语法数据类型 (*指针名)[长度]括号强制*先结合变量本质是指针指向固定列长的完整数组。intarr[2][3]{1,2,3,4,5,6};int(*p)[3];// 数组指针指向“包含3个int元素的一维数组”parr;// 二维数组名arr本身就是数组指针特性所有指针变量统一占8字节64位和指向数组大小无关p偏移一整行数组字节本例3*412字节直接跳到下一行首地址二维数组传参标准写法int fun(int (*parr)[3], int row)。3.3 快速区分口诀int *a[5]→ 先看[]→指针数组数组int (*a)[5]→ 先看*→数组指针指针。3.4 二维数组与数组指针的映射关系inta[2][3]{{1,2,3},{4,5,6}};int(*q)[3]a;// 多种等价访问元素方式a[0][1];*(a[0]1);*(*(a0)1);q[0][1];*(*(q0)1);层级拆解a/q指向整行的数组指针a[m]/*(am)等价行首一维指针指向当前行第一个元素a[m][n]先取第m行首地址偏移n个int字节读取对应数值。四、const修饰指针的4种组合只读权限细分const代表只读修饰位置不同限制对象完全不同分四类场景1.const int *p/int const *p指向内容只读指针可改const修饰*p不能通过指针修改内存值但指针p可以更换指向intx1,y2;constint*px;// *p 10; 编译报错禁止修改指向内容py;// 合法指针指向可以切换2.int *const p指针本身只读内容可改const修饰指针变量p定义时必须初始化指针指向永久固定但能修改内存数据intx1;int*constpx;*p100;// 合法修改内容// p y; 编译报错不能修改指针指向3.const int *const p/int const *const p双向只读指针不可更换指向同时不能修改指向内存的值完全只读。五、指针函数 vs 函数指针概念完全割裂5.1 指针函数是函数返回值为指针语法数据类型 *函数名(形参列表)核心是函数执行结束返回一个内存地址指针。// 返回char*字符串地址char*get_msg(void);⚠️ 致命禁忌绝对不能返回局部变量的地址局部变量存储在栈区函数执行结束栈内存自动回收返回野指针导致程序崩溃仅能返回全局变量、静态局部变量、堆内存地址。5.2 函数指针是指针指向一段函数代码语法返回值类型 (*指针名)(形参类型)存储函数在文本区的代码首地址可间接调用函数、用于回调函数。intadd(inta,intb){returnab;}int(*func_p)(int,int)add;// 两种等价调用方式intresfunc_p(1,2);intres(*func_p)(1,2);六、补充野指针与空指针指针安全基础空指针 NULL宏定义#define NULL ((void *)0)指向地址0该内存为操作系统保护只读区域禁止解引用*NULL否则程序段错误用于指针初始化标记指针无有效指向。int*pNULL;// 规范初始化避免野指针野指针两类来源① 未初始化的局部指针② 指向已释放/回收的内存。野指针指向随机非法地址解引用会随机崩溃开发规范所有指针定义时初始化为NULL。七、指针体系总结void* 万能指针无类型必须强转才能解引用是通用内存操作的基础二级指针**用于修改外部一级指针、接收指针数组指针数组存指针的数组数组指针指向完整数组的指针二维数组传参依赖数组指针const分四类修饰规则区分限制「指针本身」还是「指向内容」指针函数返回地址函数指针存储函数入口二者不要混淆所有指针操作优先初始化NULL杜绝野指针保证程序稳定性。