3.揭秘C语言指针:不是玄学,只是地址与类型的游戏

理解指针的本质

指针是存储内存地址的变量。它的核心功能是记录某个数据在内存中的位置,而非数据本身。例如:

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*对同一地址的数据解释不同
  • 类型不匹配可能导致数据解析错误

嵌入式开发中的典型应用

  1. 寄存器映射
    直接通过指针访问硬件寄存器:

    #define GPIO_BASE 0x40020000
    volatile uint32_t *GPIO_MODE = (uint32_t*)(GPIO_BASE + 0x00);
    *GPIO_MODE = 0xAB;  // 写入寄存器
    

     

  2. 动态内存管理
    使用指针操作堆内存:

    int *arr = malloc(10 * sizeof(int));  // 动态分配数组
    arr[0] = 100;  // 通过指针访问
    

     

  3. 数据结构与协议处理
    指针常用于链表、缓冲区等场景:

    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;  // 越界写入
    

     

学习指针的核心方法

  1. 画内存图
    可视化指针与变量的关系,明确地址和值的对应关系。

  2. 调试观察
    使用调试器查看指针地址和解引用后的值。

  3. 分步验证

    • 先确认指针是否指向有效地址
    • 再检查类型是否正确
    • 最后验证操作是否影响预期内存

指针与数组的关系

数组名可视为指向首元素的指针:

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

 

通过理解上述原则,指针将不再是抽象概念,而是精确控制内存的工具。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值