尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

嵌入式学习 day13:指针进阶

嵌入式学习 day13:指针进阶
📅 发布时间:2026/8/4 6:33:28

一、void指针

1. 概念

void *是无类型指针(泛型指针),可以存放任意类型指针的值。

c

void *p; // 无类型指针 char *cp; int *ip; double *dp; p = cp; // ✅ 任意指针都能赋给void * p = ip; p = dp;

2. 使用场景

(1)存放任意内存地址

c

void *p = (void *)0x12345678; // 存放一个绝对地址

(2)作为函数参数传递任意类型指针

c

void swap(void *a, void *b, int size) { // 按字节交换内存块 }

void *类型的参数可以接收任意类型的指针,配合size参数可以实现"通用交换函数"。

void指针不能直接解引用,必须先转换为具体类型:

c

int num = 10; void *p = # printf("%d\n", *p); // ❌ void *不能解引用 printf("%d\n", *(int *)p); // ✅ 先转为int *再解引用

二、二级指针

1. 概念

二级指针是指向指针的指针,存的是指针变量的地址。

c

int a = 100; int *p = &a; // p指向a int **q = &p; // q指向p

逐级解引用:

c

printf("%d\n", **q); // 输出100

理解过程:

  • q存的是p的地址

  • *q取到p的内容(即a的地址)

  • **q取到a的内容(即100)

2. 二级指针的用途

(1)修改指针变量的指向

函数内想修改函数外指针变量的值,需要传指针变量的地址(即二级指针)。

c

void allocate(int **pp, int size) { *pp = (int *)malloc(size * sizeof(int)); } int main(void) { int *p = NULL; allocate(&p, 10); // 传入p的地址 // p现在指向动态分配的空间 return 0; }
(2) 指针数组传参

c

void print_strings(char **str, int len) { for (int i = 0; i < len; i++) { printf("%s\n", str[i]); } } int main(void) { char *str[3] = {"hello", "world", "C"}; print_strings(str, 3); // 指针数组名→char** return 0; }

三、指针数组和数组指针

1. 指针数组(本质是数组)

数组的每个元素都是指针。

c

int *a[5]; // 有5个元素,每个都是 int* 类型,占40字节(64位系统)

使用场景:操作字符串数组(比二维字符数组更高效)。

c

char *str[3] = {"hello", "world", "C"}; printf("%s\n", str[0]); // 输出hello

指针数组只存地址(字符串在常量区),二维字符数组存完整副本(字符串在数组内)。指针数组更省空间,但指向的内容通常是只读的。

2. 数组指针(本质是指针)

指向数组的指针。

c

int (*p)[5]; // p指向一个有5个int元素的数组,p占8字节

与一维数组的关系:

c

int a[5] = {1, 2, 3, 4, 5}; int (*p)[5] = &a; // 指向整个数组

之前学过:一维数组名a通常理解为int *(指向首元素),但有两种情况例外:

  • sizeof(a):计算整个数组大小

  • &a:取整个数组的地址,类型为int (*)[5]

c

int a[5]; printf("%p\n", a); // 指向第一个元素 printf("%p\n", &a); // 指向整个数组,值相同但类型不同

数组指针取*,值不变,类型降级:

c

int (*p)[5] = &a; printf("%p\n", *p); // 与a的值相同,类型变为 int *

3. 指针数组 vs 数组指针

指针数组数组指针
写法int *a[5]int (*p)[5]
本质数组指针
运算符优先级[]优先括号优先
大小5×8=40字节8字节

四、二维数组与指针的关系

1. 二维数组的地址结构

c

int a[2][3] = {{1,2,3}, {4,5,6}};
表达式含义类型
a指向第一行的数组指针int (*)[3]
a[0]第一行第一个元素的指针int *
a[1]第二行第一个元素的指针int *
&a[0][0]第一个元素的指针int *

二维数组的数组名a和一维数组的数组名a含义不同,一维数组名指向首元素,二维数组名指向第一行(整个行数组)。

2. 访问第m行第n列元素的等价写法

c

a[m][n] // 最直观 *(a[m] + n) // 先取第m行指针,再偏移 *(*(a + m) + n) // 先偏移到第m行,再解引用取行指针,再偏移 *(*(a + m) + n) // 通用公式

如果已知首元素指针p = &a[0][0],总列数为N:

c

*(p + m * N + n) // 按一维方式偏移

如果已知数组指针q = a:

c

*(*(q + m) + n) // 与上面第3种等价 *(q[m] + n) // q[m]等价于*(q+m)

3. 二维数组传参

二维数组传参需要传递数组指针和行数。

c

int fun(int (*parray)[3], int row); // 方式1:数组指针 int fun(int parray[][3], int row); // 方式2:二维数组形式(等价)

c

void print_array(int (*arr)[3], int row) { for (int i = 0; i < row; i++) { for (int j = 0; j < 3; j++) { printf("%d ", arr[i][j]); } printf("\n"); } } int main(void) { int a[2][3] = {{1,2,3}, {4,5,6}}; print_array(a, 2); // 传数组名和行数 return 0; }

二维数组传参时列数不能省略,但行数可以省略。

五、今日总结

今天的核心要点如下:

void指针:

  • 无类型指针,可以存放任意类型指针

  • 不能直接解引用,必须强转类型

  • 常用于通用函数设计(如qsort、memcpy)

二级指针:

  • 指向指针的指针,存的是指针变量的地址

  • 用途:修改函数外指针变量的指向、指针数组传参

  • 解引用:**q逐级取值

指针数组 vs 数组指针:

  • int *a[5]:指针数组(数组),存指针

  • int (*p)[5]:数组指针(指针),指向数组

  • 区分关键:看运算符优先级和括号

二维数组与指针:

  • a是int (*)[N]类型(指向行的数组指针)

  • a[i]是int *类型(指向第i行首元素)

  • 访问元素:a[m][n]、*(a[m]+n)、*(*(a+m)+n)

  • 传参:列数不能省略,行数可省

今日感悟:

指针是c语言学习的一大难点。void *是实现泛型编程的基础;二级指针若没有理解,画图后思路就清晰了;指针数组和数组指针的区分关键在于运算符优先级;二维数组和指针的关系虽然复杂,但掌握a、a[i]、&a三者的类型区别,就能应对大多数场景。

相关新闻

  • 从Docker到Kubernetes Operator:OpenClaw部署架构演进与实战指南
  • UnityMMO框架设计:从状态同步到ECS混合架构的实战解析
  • Spring Boot 3 REST API 工程化实践:校验、异常、日志与测试

最新新闻

  • Wi-Fi天线原理与实战调优:从增益、极化到MIMO,彻底改善信号质量
  • RocketMQ 的“全局画面
  • 软件公司生存策略:火箭模式与印钞机模式解析
  • 3步解锁网易云音乐:让加密NCM文件重获播放自由
  • 从零构建纯净Win10 PE:定制化系统维护环境的完整指南
  • Java枚举类深度解析:原理、应用与性能优化

日新闻

  • 5分钟快速搭建智能数字人:Live2D虚拟形象终极部署指南
  • 告别繁简字幕转换烦恼:这款开源工具让你一键搞定影视字幕处理 [特殊字符]
  • GPT-5.4传闻背后:大模型永久记忆与极限推理的技术演进与挑战

周新闻

  • 怀化母婴除甲醛公司测甲醛中心怎么选:康之居母婴除甲醛标准、流程、避坑指南 - 信誉隆金银铂奢回收
  • 三步打造你的终极音乐中心:foobox-cn网络电台功能完整指南
  • Lance湖仓格式:为多模态AI工作流设计的终极数据存储方案

月新闻

  • ClickHouse版本管理深度实战:4步构建零风险升级与回滚体系
  • Java 23 种设计模式:从踩坑到精通 | 番外:责任链模式 —— 物流审批流程实战
  • 华硕笔记本性能解放指南:G-Helper轻量级控制工具全面解析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号