嵌入式之指针

news2025/2/24 12:07:18

在嵌入式系统中指针是一种非常重要的概念。它们用于直接访问内存地址,能够提高程序的灵活性和效率。

一、基本概念

1. 指针的基本概念

  • 定义:指针是一个变量,其值为另一个变量的地址。通过指针,可以间接访问和修改该变量的值。
  • 声明:在C语言中,指针的声明格式为 类型 *指针名,例如 int *p 表示 p 是一个指向整数的指针。

2. 指针的使用

  • 动态内存分配:在嵌入式系统中,动态内存分配(如使用 malloc)可以根据需要分配内存,但要注意内存的管理,避免内存泄漏。
  • 数组和指针:数组名在大多数情况下可以看作是指向数组首元素的指针。通过指针可以方便地遍历数组。
  • 函数参数:使用指针作为函数参数,可以实现对原始数据的修改,避免数据的复制,提高效率。

3. 指针的类型

  • 普通指针:指向基本数据类型(如 intchar 等)。
  • 结构体指针:指向结构体类型,可以方便地访问结构体中的各个成员。
  • 函数指针:指向函数的指针,可以实现回调机制,增加程序的灵活性。

4. 指针的注意事项

  • 指针的初始化:使用指针前应确保其已被初始化,避免出现野指针(即指向未知地址的指针)。
  • 内存管理:在嵌入式系统中,内存资源往往有限,因此要谨慎使用动态内存,尽量避免频繁分配和释放内存。
  • 越界访问:使用指针时要注意数组的边界,避免越界访问,导致未定义行为。

二、指针类型

1. 普通指针

普通指针用于指向基本数据类型(int、char)。它们可以用于动态内存管理、数组操作和函数参数传递等场景。

例子:普通指针的基本用法

#include <stdio.h>

int main() {
    int a = 10;          // 定义一个整数
    int *p = &a;        // 声明一个指针并初始化为 a 的地址

    printf("Value of a: %d\n", a);     // 输出 a 的值
    printf("Value via pointer: %d\n", *p); // 通过指针访问 a 的值

    *p = 20; // 通过指针修改 a 的值
    printf("New value of a: %d\n", a); // 输出修改后的 a 的值

    return 0;
}

应用场景

  • 动态内存分配:使用 mallocfree 进行动态内存管理。
  • 数组操作:通过指针遍历和操作数组元素。
  • 函数参数传递:避免大数据结构的复制,提高性能。

2. 结构体指针

结构体指针用于指向结构体类型,可以方便地访问结构体中的各个成员。

例子:结构体指针的用法

#include <stdio.h>
#include <string.h>

typedef struct {
    char name[20];
    int age;
} Person;

int main() {
    Person person;               // 定义一个结构体变量
    Person *pPerson = &person;  // 声明一个指向结构体的指针

    // 使用结构体指针访问和修改成员
    strcpy(pPerson->name, "Alice");
    pPerson->age = 30;

    printf("Name: %s, Age: %d\n", pPerson->name, pPerson->age);

    return 0;
}

应用场景

  • 数据组织:使用结构体指针管理复杂数据结构(如链表、树等)。
  • 函数参数传递:通过结构体指针传递大型结构体,避免复制,提高效率。

3. 函数指针

函数指针是指向函数的指针,可以用来实现回调机制、事件处理等。

例子:函数指针的用法

#include <stdio.h>

// 定义一个函数类型
typedef void (*Operation)(int, int);

// 加法函数
void add(int a, int b) {
    printf("Sum: %d\n", a + b);
}

// 减法函数
void subtract(int a, int b) {
    printf("Difference: %d\n", a - b);
}

// 执行操作的函数
void executeOperation(Operation op, int x, int y) {
    op(x, y); // 调用传入的函数指针
}

int main() {
    // 声明函数指针并指向加法和减法函数
    Operation op1 = add;
    Operation op2 = subtract;

    // 执行操作
    executeOperation(op1, 10, 5); // 调用加法
    executeOperation(op2, 10, 5); // 调用减法

    return 0;
}

应用场景

  • 回调函数:在事件驱动编程中,使用函数指针作为回调。
  • 策略模式:根据不同的条件选择不同的函数执行。
  • 状态机:通过函数指针实现不同状态下的行为。

三、易混辨别

1. 常量指针与指针常量

1.1 常量指针

常量指针是指指针所指向的内容是常量,不能通过该指针修改其指向的值。常量指针的语法是 const 类型 *指针名

#include <stdio.h>

void printValue(const int *ptr) {
    // ptr指向的值是常量,不能通过ptr修改
    printf("Value: %d\n", *ptr);
    // *ptr = 20; // 错误:不能修改常量
}

int main() {
    int a = 10;
    const int *p = &a; // p是一个常量指针,指向整数

    printValue(p); // 输出值
    // *p = 15; // 错误:不能通过常量指针修改值

    return 0;
}
  • 保护数据:常量指针用于保护指向的数据不被修改,适合于需要只读访问的场景。
  • 函数参数:在函数参数中使用常量指针,可以避免不小心修改传入的变量。

1.2 指针常量

指针常量是指指针本身的值是常量,不能改变指向的地址。指针常量的语法是 类型 * const 指针名

#include <stdio.h>

int main() {
    int a = 10;
    int b = 20;
    int * const p = &a; // p是一个指针常量,指向整数

    printf("Value pointed by p: %d\n", *p); // 输出a的值

    *p = 15; // 可以通过指针修改指向的值
    printf("New value of a: %d\n", a); // 输出修改后的a的值

    // p = &b; // 错误:不能改变指针常量的指向

    return 0;
}
  • 固定指针:指针常量用于确保指针在其生命周期内指向同一地址,适合需要固定指向某个数据的场景。
  • 避免意外更改:在复杂的函数中,确保指针不被意外更改,增加代码的可读性和安全性。

1.3 常量指针与指针常量的区别

特性常量指针 (const T*)指针常量 (T* const)
修改指向的内容不可修改可修改
修改指针的地址可修改不可修改
语法const int *pint * const p
  • 常量指针:指向的内容不可修改,但指针本身可以指向其他地址。
  • 指针常量:指针本身不可修改,但可以通过指针修改指向的内容。
  • 结合使用:可以创建一个指向常量的指针常量,既不能修改指向的内容,也不能改变指针的指向。

1.4 结合使用

常量指针和指针常量可以结合使用,形成一个指向常量的指针常量,语法为 const 类型 * const 指针名

#include <stdio.h>

int main() {
    int a = 10;
    const int * const p = &a; // p是一个指向常量的指针常量

    printf("Value pointed by p: %d\n", *p); // 输出a的值

    // *p = 15; // 错误:不能通过常量指针修改值
    // p = &b; // 错误:不能改变指针常量的指向

    return 0;
}

2. 函数指针与指针函数

2.1 函数指针

概念

  • 函数指针是一个变量,它存储的是一个函数的地址。通过函数指针,可以调用指向的函数,就像直接调用函数一样。
#include <iostream>

// 定义两个简单的函数
int add(int a, int b) {
    return a + b;
}

int subtract(int a, int b) {
    return a - b;
}

// 定义一个函数指针类型
typedef int (*Operation)(int, int);

void performOperation(Operation op, int x, int y) {
    std::cout << "Result: " << op(x, y) << std::endl;
}

int main() {
    // 使用函数指针调用不同的函数
    performOperation(add, 5, 3);      // 输出: Result: 8
    performOperation(subtract, 5, 3); // 输出: Result: 2

    return 0;
}

用途

  • 动态函数调用:可以在运行时决定调用哪个函数。
  • 回调机制:将函数指针作为参数传递给另一个函数,实现回调。
  • 实现策略模式:通过函数指针选择不同的算法或策略。

2.2 指针函数

概念

  • 指针函数是一个返回指针的函数。函数的返回类型是一个指针类型。

例子

#include <iostream>

// 返回一个指向数组中最大元素的指针
int* findMax(int* arr, int size) {
    if (size <= 0) return nullptr;

    int* max = &arr[0];
    for (int i = 1; i < size; ++i) {
        if (arr[i] > *max) {
            max = &arr[i];
        }
    }
    return max;
}

int main() {
    int numbers[] = {1, 5, 3, 9, 2};
    int size = sizeof(numbers) / sizeof(numbers[0]);

    int* maxPtr = findMax(numbers, size);
    if (maxPtr != nullptr) {
        std::cout << "Max value: " << *maxPtr << std::endl; // 输出: Max value: 9
    }

    return 0;
}

用途

  • 返回动态内存地址:指针函数常用于返回动态分配的内存地址。
  • 返回复杂数据结构的地址:例如返回数组中某个元素的地址。
  • 链表或树结构的导航:在数据结构中,指针函数可以用于遍历或查找节点。

总结如下:

特性函数指针指针函数
定义存储函数地址的指针变量。返回指针类型的函数。
语法return_type (*pointer_name)(parameter_list);return_type* function_name(parameter_list);
用途用于动态调用函数、实现回调机制、策略模式等。用于返回动态内存地址或复杂数据结构的地址。
应用场景- 回调函数实现 - 动态函数选择 - 策略模式实现- 返回数组或对象的地址 - 链表或树节点的导航
调用方式通过解引用指针来调用所指向的函数。直接调用函数以获得返回的指针。
示例int (*funcPtr)(int, int) = add;int* findMax(int* arr, int size);
灵活性高,因为可以在运行时选择不同的函数进行调用。提供了一种返回复杂数据结构或动态内存的方式。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2304382.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HTTP SSE 实现

参考&#xff1a; SSE协议 SSE技术详解&#xff1a;使用 HTTP 做服务端数据推送应用的技术 一句概扩 SSE可理解为&#xff1a;服务端和客户端建立连接之后双方均保持连接&#xff0c;但仅支持服务端向客户端推送数据。推送完毕之后关闭连接&#xff0c;无状态行。 下面是基于…

二分图检测算法以及最大匹配算法(C++)

上一节我们学习了有向图中的最大连通分量. 本节我们来学习二分图. 二分图是一种特殊的图结构, 能够帮助我们高效地解决这些匹配和分配问题. 本文将带你了解二分图的基本概念, 判定方法, 最大匹配算法以及实际应用场景. 环境要求 本文所用样例在Windows 11以及Ubuntu 24.04上面…

Keepalive基础

一。简介和功能 vrrp协议的软件实现&#xff0c;原生设计目的是为了高可用ipvs服务 功能&#xff1a; 1.基于vrrp协议完成地址流动 2.为vip地址所在的节点生成ipvs规则&#xff08;在配置文件中预先定义&#xff09; 3.为ipvs集群的各RS做健康状况检测 4.基于脚本调用接口…

计算机毕业设计SpringBoot+Vue.jst0图书馆管理系统(源码+LW文档+PPT+讲解)

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

【Java消息队列】应对消息丢失、重复、顺序与积压的全面策略

应对消息丢失、重复、顺序与积压的全面策略 引言kafka消息丢失生产者消费者重复消费顺序消费消息积压生产者消费者其他RabbitMQ消息丢失生产者事务机制,保证生产者发送消息到 RabbitMQ Server发送方确认机制,保证消息能从交换机路由到指定队列保证消息在 RabbitMQ Server 中的…

【论文解读】TransMLA: Multi-Head Latent Attention Is All You Need

论文链接 1. 论文背景与问题动机 现代大规模语言模型&#xff08;LLM&#xff09;在推理时往往遇到通信瓶颈&#xff0c;主要原因在于自注意力机制中需要缓存大量的 Key-Value&#xff08;KV&#xff09;对。例如&#xff0c;对于 LLaMA‑65B 这种模型&#xff0c;即使采用 8…

登录-06.JWT令牌-生成和校验

一.JWT令牌的生成和校验 JWT令牌生成 想要生成JWT令牌&#xff0c;那么就要首先引入JWT令牌的相关依赖&#xff0c; <dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-api</artifactId><version>0.11.2</version>…

【Git】多人协作

文章目录 完成准备工作多人协作场景一场景二远程分支删除后&#xff0c;本地 git branch -a 依然能看到的解决办法 完成准备工作 在之前&#xff0c;我们所完成的工作如下&#xff1a; 基本完成 Git 的所有本地库的相关操作&#xff0c;git基本操作&#xff0c;分支理解&#…

邮件安全之发件人伪造

电子邮件工作原理 电子邮件传输过程中主要涉及到SMTP、IMAP、POP3三种协议&#xff0c;具体功能如下&#xff1a; SMTP:全称Simple Mail Transfer Protocol&#xff0c;即简单邮件传输协议&#xff0c;主要用于发送邮件&#xff0c;使用端口号25。 IMAP:全称Internet Mail Acce…

使用 AIStor 和 OpenSearch 增强搜索功能

在这篇文章中&#xff0c;我们将探讨搜索&#xff0c;特别是 OpenSearch 如何帮助我们识别模式或查看不断增长的数据中的趋势。例如&#xff0c;如果您正在查看运营数据&#xff0c;如果您的服务似乎是随机的&#xff0c;那么您需要尽可能回溯以识别模式并找出原因。这不仅适用…

【LLM】R1复现项目(SimpleRL、OpenR1、LogitRL、TinyZero)持续更新

note &#xff08;1&#xff09;未来的工作需亟待解决&#xff1a; 支持大规模 RL 训练&#xff08;PPO、GRPO 等&#xff09;的开源基础框架用于稳定训练的 GRPO 训练超参的自动化调优RL 训练数据的配比&#xff08;难度、领域、任务等&#xff09;基于 Instruct 模型训练 R…

买股票的最佳时机 - 2

买卖股票的最佳时机 III 题目描述&#xff1a; 提示&#xff1a; 1 < prices.length < 1050 < prices[i] < 105 分析过程&#xff1a; 写动态规划&#xff0c;我们需要考虑一下问题&#xff1a; 定义状态状态转移方程初始条件 遍历顺序 4种状态&#xff1a; …

Python基于flask的智慧交通可视化,大数据智慧交通数据可视化系统

博主介绍&#xff1a;✌程序员徐师兄、8年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战*✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447…

【Unity】鱼群效果模拟

鱼群效果模拟 文章目录 鱼群效果模拟Boid算法实现方式version1_CPUversion2_GPUversion3_Multilaterationversion4_Bitonic_Sorting &#xff08;GPU友好&#xff09;version5_Skinning &#xff08;TODO&#xff09; 细节项优化项参考链接 Boid算法 Boid算法是一种模拟群体行…

云图库平台(五)——后端图片模块开发

目录 一、需求分析二、库表设计三、图片的处理如何实现图片的上传和下载创建图片的业务流程如何对图片进行解析 四、创建并使用对象存储五、后端操作对象存储初始化客户端通用能力类文档上传文件下载 一、需求分析 管理员功能&#xff1a; 图片的上传和创建&#xff1a;仅管理…

postman调用ollama的api

按照如下设置&#xff0c;不需要设置key 保持长会话的方法 # 首次请求 curl http://localhost:11434/api/generate -d {"model": "deepseek-r1:32b","prompt": "请永久记住&#xff1a;110&#xff0c;1-12&#xff0c;之后所有数学计算必…

十、OSG学习笔记-多线程(OpenThreads)

上一节内容&#xff1a; 九、OSG学习笔记-NodeVisitor节点遍历器-CSDN博客https://blog.csdn.net/weixin_36323170/article/details/145742756?spm1001.2014.3001.5501 本章节代码&#xff1a; OsgStudy/Openthreads CuiQingCheng/OsgStudy - 码云 - 开源中国https://gite…

DeepSeek 助力 Vue 开发:打造丝滑的单选按钮(Radio Button)

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 Deep…

【行业解决方案篇十八】【DeepSeek航空航天:故障诊断专家系统 】

引言:为什么说这是“航天故障终结者”? 2025年春节刚过,航天宏图突然官宣"DeepSeek已在天权智能体上线",这个搭载在卫星和空间站上的神秘系统,号称能提前48小时预判99.97%的航天器故障。这不禁让人想起年初NASA禁用DeepSeek引发的轩然大波,更让人好奇:这套系…

谷歌浏览器更新后导致的刷新数据无法显示

这几天突然出现的问题&#xff0c;就是我做了一个网站&#xff0c;一直用Google展示&#xff0c;前两天突然就是刷新会丢失数据&#xff0c;然后再刷新几次吧又有了&#xff0c;之前一直好好的&#xff0c;后端也做了一些配置添加了CrossOrigin注解&#xff0c;然而换了edge浏览…