指针
取地址(&)/ 解引用(*)
类型与步长
STM32 是 32 位单片机,任何指针变量(无论指向char还是double)本身都占用4 个字节(32bit)的 RAM,用来存放一个 32 位的内存地址。
指针+1,加的字节数是根据指向的类型决定的:
char *p1; // p1 + 1 移动 1 字节 short *p2; // p2 + 1 移动 2 字节 int *p3; // p3 + 1 移动 4 字节 uint32_t *p4; // p4 + 1 移动 4 字节 void *p5; // 通用指针,不能直接++(不知道步长)这些指针的大小都是4字节,移动的步长不同。
数组与&
int arr[5]; arr; // 代表数组首元素地址(类型 int*) &arr; // 代表整个数组的地址(类型 int (*)[5]) arr + 1 // 移动 4 字节(指向 arr[1]) &arr + 1 // 移动 20 字节(跳过整个数组,指向数组末尾之后)const与volatile
const在*左边,修饰的是指向的内容;const在*右边,修饰的是指针本身
const int *p1; // 指向的内容只读(不能改 *p1),但 p1 可以指向别处 int * const p2; // 指针本身只读(不能改指向),但内容可以改 const int * const p3;// 指针和内容都只读volatile:不被编译优化。
volatile uint32_t *reg = (uint32_t*)0x40020000; // 硬件寄存器地址 // 每次读取 *reg,编译器都会去读物理地址,而不是用缓存的值多级指针与函数指针
二级指针:修改指针的值,把指针变量看成一个完整的变量
void allocate_memory(void **ptr) { // ptr 指向外部指针变量的地址 *ptr = pvPortMalloc(100); // 修改外部指针指向新分配的内存 } int *buf = NULL; allocate_memory((void**)&buf); // 传入指针的地址函数指针:
void (*task_func)(void *); // 定义一个函数指针变量 task_func = StartDefaultTask; // 赋值 task_func(NULL); // 调用 // 更复杂的例子:指向返回 int,参数为两个 int 的函数指针 int (*calculator)(int, int) = &add; int result = calculator(3, 4);malloc
void Task_A(void *arg) { int local_val = 5; // 这个变量在 Task_A 的栈上 osMessageQueuePut(queue, &local_val, 0, 0); // 传递地址 // 函数返回后,栈帧释放,这块地址可能被其他任务覆盖! }local_val这个变量创建在了进程对应的栈上,会被后续的内容覆盖,所以要么放在静态区(只有一个进程更改这个值),要么放在堆区。
使用pvProtMalloc动态分配内存
int *pData = (int*)pvPortMalloc(100 * sizeof(int)); // 申请400字节 // 2. 检查是否分配成功 if (pData != NULL) { // 3. 使用这块内存 pData[0] = 123; pData[99] = 456; // 4. 使用完毕后,释放内存 vPortFree(pData); // 5.将指针置空,防止误用 pData = NULL; }静态存储区:存放全局变量和static修饰的变量。
栈:存放进程内部创建的变量。
堆:存放动态分配的变量。
常量区:存放字符串常量。