news 2026/5/1 9:14:41

《 一次让你学会并掌握指针》嵌入式-C语言高级-指针

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
《 一次让你学会并掌握指针》嵌入式-C语言高级-指针

好的,我们来一次把C语言指针彻底搞懂,尤其是从嵌入式开发最常用的角度去讲。

目标:看完这篇后,你能自信地说“我指针基本会了”,并且能看懂90%嵌入式C代码里的指针用法。

第一步:先把最本质的概念建立(很多人一辈子都没建立)

指针最核心的3句话(请背下来):

  1. 内存的本质是编号(从0开始的整数,通常用十六进制表示)
  2. 指针变量本质上是存地址的普通变量
  3. *是“去它指向的地址里取东西/放东西”的操作符

用最直白的比喻:

内存就像一个超级长的信箱排(0号 ~ 几亿号) int a = 100; → 找一个空信箱(比如0x20000010),把100塞进去 int *p; → 买一个记事本,专门用来记“哪个信箱有东西” p = &a; → 把a的信箱号(0x20000010)写到记事本上 *p = 200; → 根据记事本上的地址去找信箱,把里面的东西改成200 printf("%d", *p); → 根据记事本去信箱看现在里面是多少 → 输出200

第二步:最常用的5种指针类型(嵌入式最常考/最常写)

写法含义嵌入式最典型用法sizeof(这个类型)
int *p指向int的指针普通变量、数组元素、结构体成员通常4字节(32位)/8字节(64位)
uint8_t *p指向字节的指针(最常用!)操作寄存器、串口收发缓冲区、I2C/SPI数据4或8字节
const uint8_t *p只读字节指针指向常量区字符串、Flash里的查找表同上
uint8_t * const p指针本身不可改(常量指针)指向固定硬件寄存器地址同上
void *p万能指针(什么都能指)malloc、memcpy、硬件寄存器映射同上

第三步:嵌入式最经典的真实写法(强烈建议全部敲一遍)

// 1. 寄存器直接操作(最常见写法)#defineGPIOA_BASE((uint32_t)0x40020000)#defineGPIOA_ODR(*(volatileuint32_t*)(GPIOA_BASE+0x14))// 等价写法(更推荐初学者这样理解)volatileuint32_t*constGPIOA_ODR=(volatileuint32_t*)(0x40020000+0x14);voidLED_ON(void){*GPIOA_ODR|=(1U<<5);// 置位 PA5}voidLED_OFF(void){*GPIOA_ODR&=~(1U<<5);// 清零 PA5}
// 2. 内存映射 + 结构体方式(现代STM32 HAL/LL最常用)typedefstruct{volatileuint32_tMODER;// 0x00volatileuint32_tOTYPER;// 0x04// ... 很多寄存器volatileuint32_tODR;// 0x14}GPIO_TypeDef;#defineGPIOA((GPIO_TypeDef*)0x40020000)voidLED_Toggle(void){GPIOA->ODR^=(1U<<5);}
// 3. 一级指针做函数参数(最常用传出多个值的方式)voidswap(int*a,int*b){inttemp=*a;*a=*b;*b=temp;}// 用法intx=10,y=20;swap(&x,&y);// 现在 x=20, y=10
// 4. 数组名就是指针(但不能 ++/-- 也不能赋值)uint8_tbuf[100];uint8_t*p=buf;// OK,等价于 &buf[0]p++;// 指向 buf[1]*(p+3)=0x55;// 等价 buf[4] = 0x55// 但下面这些都不合法:// buf++; // 错!数组名不能自增// buf = p; // 错!数组名不能被赋值
// 5. 指针数组 vs 数组指针(面试+驱动最爱考)intarr[5];// 普通数组int*ptr_arr[5];// 指针数组:5个int* (每个元素都是指针)int(*ptr_to_arr)[5];// 数组指针:指向“5个int的数组” (很少用,但驱动里常见)// 经典写法(函数指针数组)void(*task_func[])(void)={task1,task2,task3};task_func[1]();// 执行 task2()

第四步:嵌入式最容易踩的10个坑(避开这些能少debug很多天)

  1. 野指针:定义了指针但没初始化就用*p
  2. 释放后继续使用:free() / 任务结束 / 栈空间回收后还用
  3. 忘记 volatile:寄存器/共享变量/中断标志没加 volatile
  4. 指针类型对不齐uint32_t*去指uint8_t数组 → 硬件对齐硬故障
  5. 返回局部变量地址:return &local_var; → 栈被回收,变成野指针
  6. 数组传参退化int func(int a[])其实是int func(int *a)
  7. const 位置搞错const int *pvsint * const p
  8. void强制转换前没对齐*(尤其DMA、硬件寄存器)
  9. 多级指针没搞清char **argv是指针的指针
  10. sizeof(指针) ≠ sizeof(它指向的东西)(64位系统尤其明显)

第五步:快速自测清单(做完这些说明你指针基本过关)

1.inta=10;int*p=&a;++p;现在*p 是多少?(答案:非法/未定义)2.constintx=100;constint*p=&x;*p=200;// 合法吗?3.intarr[3]={1,2,3};int(*p)[3]=&arr;现在 p+1指向哪里?4.voidfunc(constuint8_t*buf,uint16_tlen);为什么 buf 用const5.volatileuint32_t*constREG=(uint32_t*)0x40000000;两个const分别限制什么?6.char*str="hello";str[0]='H';// 会发生什么?(嵌入式尤其危险)7.如何定义一个指向“函数的指针”,函数原型是voiddelay_ms(uint32_tms)8.二维数组intmat[4][5];如何用指针遍历它?(两种常用写法)

答案可以自己先写出来,再对照网上或书验证。

如果你把上面内容全部理解 + 代码都敲一遍,恭喜你——嵌入式C里最难的指针部分你已经基本掌握了

有哪一块还觉得模糊?可以直接告诉我,我再给你针对性拆解(比如多级指针、函数指针、const volatile组合、DMA指针操作等)。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 18:01:42

2025假日欺诈:利用购物季的礼品卡骗局

2025假日欺诈&#xff1a;利用购物季的礼品卡骗局 憧憬着圣诞老人丰厚回报的孩子们&#xff0c;并非唯一期待每年年底到来的人群。 一个不幸的现实是&#xff0c;每年的最后几个月为网络犯罪分子创造了完美的环境&#xff0c;因为零售交易量急剧飙升&#xff0c;供应链变得更加…

作者头像 李华
网站建设 2026/4/18 3:06:53

Python简介

Python 是一个高层次的结合了解性、编译性、互动性和面向对象的脚本语言。 Python 的设计具有很强的可读性&#xff0c;相比其他语言经常使用英文关键字&#xff0c;其他语言的一些标点符号&#xff0c;它具有比其他语言更有特色语法结构。 Python 是一种解释型语言&#xff…

作者头像 李华
网站建设 2026/5/1 8:29:54

0 基础小白如何快速入门网络安全?这份指南帮你少走弯路

0 基础小白如何快速入门网络安全&#xff1f;这份指南帮你少走弯路 一、为什么要学网络安全&#xff1f; 在互联网时代&#xff0c;网络安全早已不是 “黑客” 的专属领域。从大学生的个人信息保护&#xff0c;到企业的数据安全&#xff0c;甚至国家的网络主权&#xff0c;都离…

作者头像 李华
网站建设 2026/4/27 19:32:53

焊接机器人设计

第2章 焊接机器人的总体方案 该设计的目的是为了设计一台焊接机器人&#xff0c;本章主要对焊接机器人的机械结构部分进行设计和分析。 2.1 总体设计的思路 设计机器人大体上可分为两个阶段&#xff1a; (1) 系统分析阶段 1&#xff09;根据系统的目标&#xff0c;明确所采用机…

作者头像 李华