C指针
一、指针基础
1.不同内存变量的作用域和生命周期
2.指针与底层硬件联系紧密,指针可操作数据的地址,实现对数据的简介访问。
3.指针的使用场景:
3.1 使用指针传递大容量的参数,主函数和子函数使用的是同一套数据,避免了参数传递过程中的数据复制,提高了运行效率,减少了内存占用。
3.2 使用指针传输输出参数,利用主函数和子函数使用同一套数据的特性,实现数据的返回,可实现多返回值函数的设计
3.3 传递返回值:将模块内的公有部分返回,让主函数持有模块的’句柄‘,便于程序对指定对象的操作
3.4 访问硬件指定内存下的数据,如设备ID、对寄存器的操作等。
3.5 将复杂格式的数据转为字节,方便通信与存储。
4.指针的值存储的是变量的地址,地址的长度与CPU的位宽相关,如:
32位的CPU,地址长度是四个字节
64位的CPU,地址长度是八个字节
5.指针与数组:数组是指针的特殊表现形式而已,数组名就是指针变量名,指针的地址存储的是数组的首地址,其他复杂的数据类型同样也是存储首地址。
6.指针变量的运算:因为指针存储的是地址,所以在一般情况下指针变量只有加减运算,指针变量没加、减1,地址就会加、减对应的类型的字节数,如:short 类型的指针变量+1,地址就会偏移2个字节, int类型的指针变量+1,地址就会偏移4个字节。
7.特殊类型的指针:
7.1 void指针,俗称’通用指针‘,通常在一些系统库函数的参数会用到void指针,因为它要具备通用性,就不清楚程序员在调用此类函数时 候传递的参数是什么类型的指针。
7.2 null指针,俗称’空指针‘,通常会被赋值0.
8. 使用指针时,需要注意的事项
8.1 在对指针取内容之前,一定要确保指针指在了合法的位置,否则将会导致程序出现不可预知的错误
8.2 同级指针之间才能相互赋值,跨级赋值将会导致编译器报错或警告
二、函数指针
示例1,
#include <stdio.h> // 定义一个函数原型 void sayHello() { printf("Hello, "); } void sayWorld() { printf("World!\n"); } int main() { // 声明一个函数指针,该指针可以指向不带参数也不返回值的函数 void (*functionPtr)(); // 初始化函数指针,使其指向 sayHello 函数 functionPtr = sayHello; // 使用函数指针调用 sayHello 函数 functionPtr(); // 修改函数指针,使其指向 sayWorld 函数 functionPtr = sayWorld; // 使用函数指针调用 sayWorld 函数 functionPtr(); return 0; }
示例2
这段代码使用了 typedef
关键字来创建了一个类型别名 pFunction
,该别名指向一个无返回值、无参数的函数指针,其指向的函数使用 void 类型参数并且返回 void 类型。
具体而言,这段代码定义了一个指针 Jump_To_Application
,其类型被命名为 pFunction
,表示这个指针可以指向满足 pFunction
类型所定义的函数特征的任何函数。
这样的定义非常有用,尤其在嵌入式系统中常常用于指向程序的入口点或者跳转到其他应用程序的函数,例如系统启动时跳转到应用程序部分。
在这个例子中,JumpToApplication
函数使用了之前定义的函数指针 Jump_To_Application
来跳转到其他应用程序。
__set_MSP
是一个特殊的内联汇编函数或宏,用于设置主堆栈指针(Main Stack Pointer,MSP)的值。MSP是ARM Cortex-M处理器中的一个寄存器,用于指向主堆栈的顶部。通过设置MSP,可以指定主堆栈的起始地址。
// 定义函数指针类型别名 typedef void (*pFunction)(void); // 定义函数指针变量 pFunction Jump_To_Application; // 定义一个函数来跳转到其他应用程序
void UserApplication(void)