2026/4/16 12:03:11
网站建设
项目流程
自建网站费用,浙江建设工程信息网查询平台,建设网站服务请示,wordpress标题带竖好的#xff0c;我们来一次把C语言指针彻底搞懂#xff0c;尤其是从嵌入式开发最常用的角度去讲。
目标#xff1a;看完这篇后#xff0c;你能自信地说“我指针基本会了”#xff0c;并且能看懂90%嵌入式C代码里的指针用法。
第一步#xff1a;先把最本质的概念建立我们来一次把C语言指针彻底搞懂尤其是从嵌入式开发最常用的角度去讲。目标看完这篇后你能自信地说“我指针基本会了”并且能看懂90%嵌入式C代码里的指针用法。第一步先把最本质的概念建立很多人一辈子都没建立指针最核心的3句话请背下来内存的本质是编号从0开始的整数通常用十六进制表示指针变量本质上是存地址的普通变量*是“去它指向的地址里取东西/放东西”的操作符用最直白的比喻内存就像一个超级长的信箱排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_BASE0x14))// 等价写法更推荐初学者这样理解volatileuint32_t*constGPIOA_ODR(volatileuint32_t*)(0x400200000x14);voidLED_ON(void){*GPIOA_ODR|(1U5);// 置位 PA5}voidLED_OFF(void){*GPIOA_ODR~(1U5);// 清零 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^(1U5);}// 3. 一级指针做函数参数最常用传出多个值的方式voidswap(int*a,int*b){inttemp*a;*a*b;*btemp;}// 用法intx10,y20;swap(x,y);// 现在 x20, y10// 4. 数组名就是指针但不能 /-- 也不能赋值uint8_tbuf[100];uint8_t*pbuf;// OK等价于 buf[0]p;// 指向 buf[1]*(p3)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很多天野指针定义了指针但没初始化就用*p释放后继续使用free() / 任务结束 / 栈空间回收后还用忘记 volatile寄存器/共享变量/中断标志没加 volatile指针类型对不齐uint32_t*去指uint8_t数组 → 硬件对齐硬故障返回局部变量地址return local_var; → 栈被回收变成野指针数组传参退化int func(int a[])其实是int func(int *a)const 位置搞错const int *pvsint * const pvoid强制转换前没对齐*尤其DMA、硬件寄存器多级指针没搞清char **argv是指针的指针sizeof(指针) ≠ sizeof(它指向的东西)64位系统尤其明显第五步快速自测清单做完这些说明你指针基本过关1.inta10;int*pa;p;现在*p 是多少答案非法/未定义2.constintx100;constint*px;*p200;// 合法吗3.intarr[3]{1,2,3};int(*p)[3]arr;现在 p1指向哪里4.voidfunc(constuint8_t*buf,uint16_tlen);为什么 buf 用const5.volatileuint32_t*constREG(uint32_t*)0x40000000;两个const分别限制什么6.char*strhello;str[0]H;// 会发生什么嵌入式尤其危险7.如何定义一个指向“函数的指针”函数原型是voiddelay_ms(uint32_tms)8.二维数组intmat[4][5];如何用指针遍历它两种常用写法答案可以自己先写出来再对照网上或书验证。如果你把上面内容全部理解 代码都敲一遍恭喜你——嵌入式C里最难的指针部分你已经基本掌握了。有哪一块还觉得模糊可以直接告诉我我再给你针对性拆解比如多级指针、函数指针、const volatile组合、DMA指针操作等。