本帖最后由 dffzh 于 2025-6-12 08:41 编辑
#申请原创#
@21小跑堂
顾名思义,所谓的指针函数,也就是函数返回值类型为指针类型(返回地址)的函数,函数格式差不多就是下面这个造型: 数据类型 *函数名(形参1, …, 形参n ); 或者更直观更易看懂的造型: (数据类型 *) 函数名(形参1, …, 形参n ); 其中数据类型可以为基本数据类型(整型,浮点型等),如下声明一个返回整型指针的指针函数: - int* add(int a, int b); 或者
- (int*) add(int a, int b);
也可以为复合数据类型(最常用的应该就是结构体类型),如下声明一个返回结构体指针的指针函数: - ST_DEVICE_STATUS* get_device_status(void); 或者
- (ST_DEVICE_STATUS*) get_device_status(void);
其中ST_DEVICE_STATUS为结构体类型。 那究竟指针函数有哪些应用呢? 指针函数一般可以用来返回字符串和全局变量地址或者返回结构体指针等。 1、返回字符串和全局变量地址 可以直接返回字符串常量的地址: - char* getMessage(void)
- { return "Hello World"; // 字符串常量存储在静态区
- }
可以直接返回全局变量的地址: - int g_Value;
- int* getValue(void)
- { return &g_Value;
- }
上面为什么强调说是返回全局变量的地址呢?局部变量不行吗? 是的,不能通过上面的方式返回局部变量的地址,因为局部变量在函数结束的时候其生命周期也跟着结束了,返回的局部变量指针会变成所谓的悬垂指针(Dangling Pointer),此时你可能会正常读取到局部变量的值(但这并不代表代码正确),也可能会读取到垃圾值,甚至是程序崩溃,即所谓的未定义行为,我们来实际测试,看下结果: - int* getValue(void)
- {
- int l_value = 100; //定义一个局部变量,并初始化为100
- return &l_value; //尝试返回局部变量的地址
- }
程序编译无错误,但直接来一条警告信息,说明这种操作就存在风险了:
所以说,程序编译时我们也需要关注一下警告信息,不能只关注错误信息。 至于程序运行结果是不是100,咱们就不看了。
2、返回结构体指针 返回结构体指针其实也是指针函数的很常见的应用,它可以以一个简单操作对全局结构体变量的数据进行读写操作,非常方便;并且避免了直接暴露全局结构体变量到程序代码中。 我们来看下代码: - //定义一个结构体,记录和更新设备相关的状态信息
- typedef struct
- {
- uint8_t device_status_error;
- uint8_t device_status_alarm;
- uint8_t device_status_warning;
- } ST_DEVICE_STATUS;
- //定义一个全局结构体变量,记录设备状态信息
- ST_DEVICE_STATUS g_stDeviceStatus;
- //定义一个指针函数,返回设备状态结构体指针数据
- (ST_DEVICE_STATUS *) getDeviceStatus(void)
- {
- return &g_stDeviceStatus;
- }
- //使用指针函数
- void func(void)
- {
- ST_DEVICE_STATUS *pDeviceStatus;
- pDeviceStatus = getDeviceStatus();
- //读设备状态(读操作),相当于直接读全局变量g_stDeviceStatus
- if(pDeviceStatus-> device_status_error)
- {
-
- }
- else iif(pDeviceStatus-> device_status_alarm)
- {
-
- }
- //清除设备状态(写操作),相当于直接写全局变量g_stDeviceStatus
- pDeviceStatus-> device_status_error = 0;
- pDeviceStatus-> device_status_alarm = 0;
- }
以上的代码通过指针函数的方式封装了全局结构体变量,除了指针函数里直接操作了全局变量,其余代码完全不需要直接操作全局变量,不仅方便读写,也增强了代码的可维护性和可读性。再给大家看下作者开发的实际项目代码: 另外,还可以用来创建链表节点,看下面代码: - //定义一个指针函数,创建链表节点
- struct Node* createNode(int data)
- { struct Node* node = (struct Node*)malloc(sizeof(struct Node)); node->data = data; return node; // 返回结构体指针
- }
但是使用指针函数时也需要注意以下几点: 1、如前文所述,一定要注意,不要试图返回一个局部变量的地址; 2、函数返回值的类型和定义的类型一定要匹配; 3、 要注意区分指针函数和函数指针,后续文章会介绍函数指针,以下的对比基本上就可以看出两者的区别: 名称 | 基本格式 | 描述 | 原因 | 指针函数 | int * func(int a, int b) 或者 (int *)func(int a, int b) | 本质是一个函数,返回指针的函数 | 括号优先级大于*,func会先与右边结合,构成一个func函数 | 函数指针 | int (*func)(int a, int b) | 本质是一个指针,指向函数的指针 | *func是一个整体,指向int (int a, int b)函数的一个指针 |
|