在C语言的实际开发中,指针是非常常用的功能,不夸张的说指针是C语言的灵魂。有时甚至会用到双重指针。我在之前的项目中使用到过一些指针,现在试着做一下总结,希望能够帮忙到需要使用,但没怎么用过的初学者。我尽可能说的简单,如有不正确的地方,希望大家见谅。闲言少叙,正式开始。
-
变量在内存中的存在形式
我们定义的变量都会存放在内存中一定的地址,见下面代码:
#include <stdio.h>
int variable_example = 0;
printf("Variable's address is %d\r\n", &variable_example);
编译器为会variable_example分配一个内存空间,如0x20001000. 实际变更在内存中的存在形式如下图:
变量名 | 地址 | 变量值 |
---|---|---|
variable_example | 0x20001000 | 0 |
another_vairable... | 0x20001004 | X |
-
指针变量
指针即地址,指针变量是指值是指针(地址)的变量。见下例:
#include <stdio.h>
int variable_example = 0;
int* pointer_example = NULL;
pointer_example = &variable_example;
printf("Variable's value is %d\r\n", variable_example);
printf("Variable's address is %d\r\n", &variable_example);
printf("Pointer's value is %d\r\n", pointer_example);
printf("Pointer's address is %d\r\n", &pointer_example);
printf("The value referenced by the pointer is: %d\r\n", *pointer_example);
变更和指针变更在内存中的存在形式如下:
变量名 | 地址 | 变量值 |
---|---|---|
variable_example | 0x20001000 | 0 |
another_vairable... | 0x20001004 | X |
... | ... | X |
pointer_example | 0x20002000 | 0x20001000 |
pointer_example是个变量,它里面存的是指针,所以它是指针变量。创建时将它赋值为NULL,即为空,表示这个指针还未被赋值,不能调用。然后将变量variable_example的地址赋给了它,即pointer_example这个变量的值为variable_example的地址。
Variable's value is 0
Variable's address is 0x20001000
Pointer's value is 0x20001000
Pointer's address is 0x20002000
The value referenced by the pointer is: 0
-
指针变量的类型
指针变量的类型,指的是存放在指针所指向地址中的变量的类型。如示例中的int*,整型指针类型,指的是指针所指向的地址中存放的变量是整型,指针本身的类型初始是固定的。拿32位系统来说,指针本身的类型就是32位的无符号整型。
-
指向指针的指针 -- 双重指针
试想一下这样的需求场景:为产品的实时状态信息做一个接口函数,供其他模块来获取这些实时状态。产品的实时状态是指产品运行时的一些过程数据,比如电机电流。有多个模块会用到电机电流,比如电机控制、电机保护、电流显示等等。首先做如下设计。
int Get_Porcess_Data(int id)
{
...
return process_data_list[n];
}
以id去索引去查询process data list,并返回相应的结果。这个实现了数据查询,但这个问题:没有执行正确与否的指示,即没有返回错误码。产品中比较重要的接口,需要返回错误码来指示接口是否运行正确,来增加产品的可靠性和稳定性。因此改进设计如下。
ERR_TYPE Get_Porcess_Data(int id, int* value)
{
...
*value = process_data_list[n];
return NO_ERR;
}
这个改进的接口,实现了运行状态反馈,但还有一个问题:调用这个接口产生了一个过程数据的备份。调用此接口时一般为这样:
int motor_current = 0;
ERR_TYPE err_code = NO_ERR;
err_code = Get_Process_Data(0x01, &motor_current);
变量motor_current即为过程数据表process_data_list中电机电流的一个备份,这个备份只有调用接口时才会更新。如何不产生这个备份呢?双重指针能解决这个问题。再次改进设计如下:
ERR_TYPE Get_Porcess_Data(int id, int** value)
{
...
*value = &process_data_list[n];
return NO_ERR;
}
调用此接口时一般类似如下操作:
int* motor_current = NULL;
ERR_TYPE err_code = NO_ERR;
err_code = Get_Process_Data(0x01, &motor_current);
if(*motor_current > CURRENT_LIMIT)
{
// Report motor current alarm
}
调用接口Get_Process_Data后,指针变量的值变为process_data_list中电机电流的地址,即指针变量指向了process data list中的电机电流,而不是备份。这样调用*motor_current时,始终取的是process data list中的实时值,而不用再次调用接口去刷新备份值了。