理解指针的本质
指针是存储内存地址的变量。它的核心功能是记录某个数据在内存中的位置,而非数据本身。例如:
int a = 42;
int *p = &a; // p存储a的地址
&a获取变量a的地址p的类型int*表明它指向的是int类型数据
关键操作符:&和*
-
取地址符
&
获取变量的内存地址。如&a返回a的存储位置。 -
解引用符
*
通过指针访问目标数据。*p等同于访问p指向的值(即a的值42)。
指针类型的意义
指针类型决定编译器如何解释内存中的数据:
float *fp = (float*)&a; // 将a的地址强制转为float指针
int*和float*对同一地址的数据解释不同- 类型不匹配可能导致数据解析错误
嵌入式开发中的典型应用
-
寄存器映射
直接通过指针访问硬件寄存器:#define GPIO_BASE 0x40020000 volatile uint32_t *GPIO_MODE = (uint32_t*)(GPIO_BASE + 0x00); *GPIO_MODE = 0xAB; // 写入寄存器 -
动态内存管理
使用指针操作堆内存:int *arr = malloc(10 * sizeof(int)); // 动态分配数组 arr[0] = 100; // 通过指针访问 -
数据结构与协议处理
指针常用于链表、缓冲区等场景:struct Packet { uint8_t cmd; uint32_t data; }; struct Packet *pkt = (struct Packet*)buffer; // 协议解析
常见风险与规避
-
野指针
未初始化的指针可能指向非法地址:int *p; // 未初始化 *p = 10; // 崩溃风险解决方法:初始化时赋值
NULL或有效地址。 -
越界访问
指针算术超出合法范围:int arr[5]; int *p = &arr[0]; *(p + 10) = 1; // 越界写入
学习指针的核心方法
-
画内存图
可视化指针与变量的关系,明确地址和值的对应关系。 -
调试观察
使用调试器查看指针地址和解引用后的值。 -
分步验证
- 先确认指针是否指向有效地址
- 再检查类型是否正确
- 最后验证操作是否影响预期内存
指针与数组的关系
数组名可视为指向首元素的指针:
int arr[3] = {1, 2, 3};
int *p = arr; // p指向arr[0]
printf("%d", *p); // 输出1
但数组名不是变量,不能重新赋值(如arr = p非法)。
多级指针的使用
指向指针的指针用于间接访问:
int a = 10;
int *p = &a;
int **pp = &p; // pp存储p的地址
printf("%d", **pp); // 输出10
常见于动态二维数组或函数参数传递。
函数指针的用途
将函数作为参数传递或实现回调:
void callback(int x) { printf("%d", x); }
void run_func(void (*func)(int), int val) { func(val); }
run_func(callback, 42); // 输出42
通过理解上述原则,指针将不再是抽象概念,而是精确控制内存的工具。

1万+

被折叠的 条评论
为什么被折叠?



