当前位置: 首页 > news >正文

【嵌入式C语言】指针数组结构体

指针与数组

  • 指针与数组
    • 指针数组
    • 数组指针
  • 多维数组
    • 数组名的保存
  • 结构体
    • 定义结构体
    • 定义结构体变量
    • 使用typedef简化结构体声明
    • 访问结构体成员
    • 结构体内存分配
    • 字节对齐
    • 位域
      • 定义位域
      • 位域的限制
      • 示例

指针与数组


指针数组和数组指针是两个不同的概念,它们涉及到指针和数组的组合使用。

指针数组

  • 定义: 指针数组是一个数组,其中的每个元素都是一个指针。
  • 示例: int *ptrArray[5]; 声明了一个包含5个元素的指针数组,每个元素都是一个指向整数的指针。
  • 用途: 指针数组常用于存储一组指针,每个指针可以指向不同类型的数据或不同位置的数组。
#include <stdio.h>
int main()
{char a[5] = {'a', 'b', 'c', 'd', 'e'};char *p[5];printf("sizeof(a) = %d\n", sizeof(a));printf("sizeof(p) = %d\n", sizeof(p));return 0;
}

输出

cd 'e:\CProject\output'
PS E:\CProject\output> & .\'指针数组.exe'
sizeof(a) = 5
sizeof(p) = 40

可以看到指针数组的大小是个数*对应类型的指针的大小

举例2

#include <stdio.h>
int main() {int a = 1, b = 2, c = 3;int *ptrArray[3] = {&a, &b, &c};// 打印指针数组中每个元素指向的值for (int i = 0; i < 3; i++) {printf("%d ", *ptrArray[i]);}return 0;
}

输出

PS E:\CProject\output> cd 'e:\CProject\output'
PS E:\CProject\output> & .\'指针数组.exe'
1 2 3 

在这个例子中,ptrArray 是一个包含3个指针的数组,每个指针分别指向整数变量 abc

数组指针

  • 定义: 数组指针是一个指针,它指向一个数组。
  • 示例: int (*ptr)[5]; 声明了一个指针,指向包含5个元素的整数数组。
  • 用途: 数组指针常用于处理二维数组或作为指向动态分配数组的指针。
#include <stdio.h>
int main() {int arr[3][5] = {{1, 2, 3, 4, 5}, {6, 7, 8, 9, 10}, {11, 12, 13, 14, 15}};int (*ptr)[5] = arr;// 打印数组指针指向的数组中的元素for (int i = 0; i < 3; i++) {for (int j = 0; j < 5; j++) {printf("%d ", ptr[i][j]);}printf("\n");}return 0;
}

在这个例子中,ptr 是一个指针,指向包含5个元素的整数数组,它被初始化为指向二维数组 arr 的第一行。

总体而言,指针数组和数组指针提供了在数组和指针之间灵活切换的方式,依赖于实际需求选择使用哪一种形式。


多维数组

数组名的保存

  • 定义一个指针,指向int a[10];的首地址
  • 定义一个指针,指向int b[5][6];的首地址
#include <stdio.h>
int main()
{int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};int b[3][4];int *p1 = a;int **p2 = b;	// 这样是错误的,二维数组和二维指针没有关系return 0;
}

这样是错误的,二维数组和二维指针没有关系

二维数组是一行一行读取的,一次就读取4列的数据

二维指针是存储线性的地址

正确的读取方式

#include <stdio.h>
int main()
{int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};int b[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};int *p1 = a;int(*p2)[4] = b; // 每次读4个printf("%d\n\n", *p1);printf("%d\n", *p2[0]);printf("%d\n", *p2[1]);printf("%d\n", *p2[2]);return 0;
}

举例2

int c[2][3][4];
int (*p)[3][4];	//T

结构体

C语言中的结构体(struct)是一种用户自定义的数据类型,它允许你将不同类型的数据组合在一起。这使得你可以创建更复杂的数据结构来表示现实世界中的实体。一个结构体可以包含多个成员(member),每个成员都有自己的数据类型和名称。

下面是一些关于C语言结构体的基本概念和用法:

定义结构体

要定义一个结构体,你需要使用struct关键字,后跟结构体的标签(可选),接着是花括号包围的一系列成员声明,最后以分号结束。

struct Point {int x;int y;
};

定义结构体变量

一旦定义了结构体,就可以声明该结构体类型的变量。有两种方式来做这件事:

  1. 在定义结构体的同时声明变量:
struct Point pt1, pt2;
  1. 先定义结构体,然后在其他地方声明变量:
struct Point;// ... 之后某个地方struct Point pt1, pt2;

如果你给结构体指定了标签(如上面例子中的Point),那么可以在后续代码中仅使用struct Point来声明新的变量。

使用typedef简化结构体声明

为了简化结构体变量的声明,通常会与typedef一起使用:

typedef struct {int x;int y;
} Point;

这样,以后可以直接使用Point作为类型名来声明结构体变量,而不需要再写struct Point

访问结构体成员

结构体成员通过点运算符.来访问:

pt1.x = 10;
pt1.y = 20;

如果结构体是指针,则使用箭头运算符->来访问成员:

Point *p = &pt1;
p->x = 30; // 等价于 (*p).x = 30;

结构体内存分配

结构体变量的内存是在声明时分配的。如果你需要动态分配结构体的内存,可以使用malloc()calloc()函数。

Point *p = (Point *)malloc(sizeof(Point));
if (p != NULL) {p->x = 40;p->y = 50;
}
// 使用完后记得释放内存
free(p);

字节对齐

#include <stdio.h>struct student
{char x;      // 4 字节对齐int roll;    // 4float marks; // 4
};
int main()
{struct student s1;printf("struct size: %d\n", sizeof(s1));return 0;
}

字节对齐:为了效率,希望牺牲一点空间换取时间的效率

分别看一下定义的顺序不同,占用的空间大小!

#include <stdio.h>struct student
{char x;   // 2short y;  // 2int roll; // 4
};struct stu
{char x;   // 4int roll; // 4short y;  // 4
};
int main()
{struct student s1;printf("struct size: %d\n", sizeof(s1));struct stu s2;printf("struct size: %d\n", sizeof(s2));return 0;
}

在这里插入图片描述

由于定义的顺序不同,占用的空间大小也不同!

第一种定义方式里,char剩余3bytes,可以给short类型的变量使用,如下图所示:
在这里插入图片描述

第二种定义的顺序,在内存中的分布如下
在这里插入图片描述

位域

位域(bit-fields)是C语言中的一种特殊结构体成员,它允许你定义一个特定宽度的字段,以位为单位。位域主要用于需要紧凑存储或与硬件通信的场合,比如嵌入式系统编程。

在位域中,你可以指定每个成员占用的位数,这可以减少内存的使用量。然而,使用位域也可能会导致代码的可移植性问题,因为不同的编译器可能对位域的实现有所不同,包括它们如何打包和对齐数据。

定义位域

位域通过在结构体成员声明后添加冒号和位宽来定义。以下是位域的一个简单例子:

struct packed_struct {unsigned int f1 : 1; // 1 bitunsigned int f2 : 3; // 3 bitsunsigned int f3 : 4; // 4 bits
};

在这个例子中,packed_struct包含三个位域成员:f1f2f3,分别占据1位、3位和4位。请注意,位域成员必须是整数类型(如intunsigned int等),并且不能是数组或指针。

位域的限制

  • 位域的大小:位域的最大宽度取决于底层整型的大小。例如,在大多数系统上,unsigned int通常是32位,所以你不能创建超过32位的位域。
  • 匿名位域:有时会看到不带名称但带有宽度的位域,这样的位域用于填充或者对齐。例如,unsigned int : 2;将占用2位,但没有关联的变量名。
  • 不可寻址性:由于位域是由多个位组成的,因此不能取位域成员的地址。
  • 端序依赖:不同体系结构上的字节顺序(大端或小端)会影响位域的实际布局。

示例

这里有一个更完整的示例,展示了如何使用位域:

#include <stdio.h>struct Flags {unsigned int flag1 : 1;unsigned int flag2 : 1;unsigned int : 6; // 匿名位域,用于填充或对齐unsigned int flag3 : 1;
};int main() {struct Flags flags;flags.flag1 = 1;flags.flag2 = 0;flags.flag3 = 1;printf("flag1: %d\n", flags.flag1);printf("flag2: %d\n", flags.flag2);printf("flag3: %d\n", flags.flag3);return 0;
}

这个程序定义了一个Flags结构体,其中包含了三个标志位,每个都只占用了1位。注意,我们还插入了一个6位的匿名位域,用于确保后续的位域从一个新的字节开始(假设编译器按照8位边界对齐)。

请记住,尽管位域提供了一种节省空间的方法,但在编写代码时应该考虑到它的可移植性和潜在的复杂性。如果你不需要精确控制位级别的数据,通常最好使用普通的结构体成员。


【嵌入式C语言】 https://www.bilibili.com/video/BV1RW411G7cr/?p=44&share_source=copy_web&vd_source=8af85e60c2df9af1f0fd23935753a933

相关文章:

【嵌入式C语言】指针数组结构体

指针与数组 指针与数组指针数组数组指针 多维数组数组名的保存 结构体定义结构体定义结构体变量使用typedef简化结构体声明访问结构体成员结构体内存分配字节对齐位域定义位域位域的限制示例 指针与数组 指针数组和数组指针是两个不同的概念&#xff0c;它们涉及到指针和数组的…...

国产数据库TiDB从入门到放弃教程

国家层面战略&#xff0c;安全的角度&#xff0c;硬件、软件国产化是趋势&#xff0c;鸿蒙电脑操作系统、鸿蒙手机操作系统…数据库也会慢慢国产化&#xff0c;国产数据库TiDB用起来比OceanBase丝滑&#xff0c;本身没有那么重。 从入门到放弃 1. 介绍1.1 TiDB 的主要特点1.2 T…...

深入解析 Spring 属性:spring.codec.max-in-memory-size

在现代 Web 应用开发中&#xff0c;数据传输的大小和效率直接影响到系统的性能和稳定性。Spring WebFlux 作为一种响应式编程框架&#xff0c;提供了强大的数据流处理能力。在使用 WebFlux 时&#xff0c;spring.codec.max-in-memory-size 是一个关键配置&#xff0c;用于定义应…...

在K8S中,如何查看Pod状态的详情?事件显示cpu不足如何处理?

在Kubernetes中&#xff0c;查看Pod状态的详细通常设计使用kubectl命令行工具&#xff0c;这是kubernetes提供的一个强大的管理工具。以下是如何查看Pod状态详情的步骤&#xff1a; 1. 查看Pod状态详情 列出所有Pod&#xff1a; 使用kubectl get pods命令可以查看集群所有Po…...

ArcGIS教程(009):ArcGIS制作校园3D展示图

文章目录 数据下载校园3D展示图制作创建要素类矢量化【楼】要素矢量化【绿地】矢量化【范围】矢量化处理打开ArcScene添加动画数据下载 https://download.csdn.net/download/WwLK123/90189025校园3D展示图制作 创建要素类 添加底图: 新建【文件地理数据库】,并修改名称为【…...

REDIS2.0

string list hash set 无序集合 声明一个key&#xff0c;键里面的值是元素&#xff0c;元素的类型是string 元素的值是唯一的&#xff0c;不能重复 多个集合类型之间可以进行并集&#xff0c;交集&#xff0c;集查的运算 sadd test1 a b c c d &#xff1a;添加5个元素&am…...

算法练习——模拟题

前言&#xff1a;模拟题的特点在于没有什么固定的技巧&#xff0c;完全考验自己的代码能力&#xff0c;因此有助于提升自己的代码水平。如果说一定有什么技巧的话&#xff0c;那就是有的模拟题能够通过找规律来简化算法。 一&#xff1a;替换所有问号 题目要求&#xff1a; 解…...

京东供应链创新与实践:应用数据驱动的库存选品和调拨算法提升履约效率

2024 年度总结系列 2024 年 10 月&#xff0c;京东零售供应链技术团队凭借其在库存选品与调拨技术上的创新与实践&#xff0c;荣获运筹与管理学领域的国际顶级奖项 Daniel H. Wagner Prize。本文为您介绍获奖背后的供应链技术创新和落地应用。 00 摘要 在电商行业中&#x…...

pytorch张量的fill_方法介绍

在 PyTorch 中&#xff0c;fill_ 是一个张量的原地操作方法&#xff0c;用于将张量中的所有元素填充为指定的值。 方法签名 Tensor.fill_(value)参数 value (float or int): 要填充到张量中的值。 返回值 返回调用该方法的张量本身&#xff0c;且是经过修改后的张量。 特…...

WAP短信格式解析及在Linux下用C语言实现

WAP短信格式解析及在Linux下用C语言实现 一、引言二、WAP短信格式概述三、WAP短信头的内容四、UDHI与WAP短信体的关系五、在Linux下用C语言解析WAP短信头及短信体内容一、引言 在移动通信领域,短信作为一种古老却稳定的通信方式,一直扮演着重要的角色。随着技术的发展,短信…...

Linux的诞生与发展、体系结构与发行版本

Linux作为一个开源操作系统&#xff0c;在过去几十年中一直扮演着至关重要的角色。它不仅深刻影响了服务器、桌面和移动设备&#xff0c;还成为了开源运动的重要组成部分。本文将介绍Linux的历史、体系结构、以及主要的发行版&#xff0c;帮助你更好地了解Linux的方方面面。 一…...

为什么Mysql用B+树作为索引

首先&#xff0c;能作为索引的数据结构有很多&#xff0c;例如数组、链表、二叉树 数据和索引都是存储在磁盘里的。 我们通过索引来查询数据时&#xff0c;先从磁盘读取索引到内存&#xff0c;再通过索引从磁盘中找到某行数据&#xff0c;然后读入到内存。 要设计一个适合 MySQ…...

探索 DC-SDK:强大的 3D 地图开发框架

在现代 Web 开发中&#xff0c;地理信息系统&#xff08;GIS&#xff09;和 3D 地图可视化变得越来越重要。dc-sdk 是一个基于 Cesium 的开源 WebGL 地图开发框架&#xff0c;它提供了丰富的地图可视化功能和简单易用的 API&#xff0c;使开发者能够轻松地在 Web 应用中集成 3D…...

C#高级篇 反射和属性详解【代码之美系列】

&#x1f380;&#x1f380;&#x1f380;代码之美系列目录&#x1f380;&#x1f380;&#x1f380; 一、C# 命名规则规范 二、C# 代码约定规范 三、C# 参数类型约束 四、浅析 B/S 应用程序体系结构原则 五、浅析 C# Async 和 Await 六、浅析 ASP.NET Core SignalR 双工通信 …...

算法 class 005 (对数器C语言实现)

对数器的概念&#xff1a; 用来测试你的算法是否正确。 怎么做呢&#xff1f; 1&#xff1a;比如&#xff0c;写个冒泡排序&#xff0c;作为对比的对象 2&#xff1a;生成一个随机数 数组&#xff0c;用来测试 3&#xff1a;用冒泡排序和你想要验证的那个排序算法&#xff0c;同…...

windows系统安装完Anaconda之后怎么激活自己的虚拟环境并打开jupyter

1.在win主菜单中找到Anaconda安装文件夹并打开终端 文件夹内有所有安装后的Anaconda的应用软件和终端窗口启动窗口 点击Anaconda Prompt&#xff08;Anaconda&#xff09;就会打开类似cmd的命令终端窗口&#xff0c;默认打开的路径是用户名下的路径 2.激活虚拟环境 使用命令…...

leetcode 面试经典 150 题:矩阵置零

链接矩阵置零题序号73题型二维数组解题方法标记数组法难度中等熟练度✅✅✅✅ 题目 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,1,1],[1,0,1]…...

SQL中的TRIM用法

TRIM 是 SQL 中用于去除字符串两端&#xff08;左侧和右侧&#xff09;的空格或特定字符的函数。这个函数常用于清理数据中的无效空白字符&#xff0c;尤其是在从外部系统导入数据时&#xff0c;常常会遇到数据两端有不必要的空格&#xff0c;使用 TRIM 可以去除这些多余的字符…...

Git Flow 工作流:保障修改不破坏主功能的完整指南20241230

Git Flow 工作流&#xff1a;保障修改不破坏主功能的完整指南 引言 在团队协作和个人项目中&#xff0c;Git Flow 是一种可靠的分支管理策略。通过清晰的分工和规范的流程&#xff0c;它能有效保障代码改动的安全性&#xff0c;避免修改破坏主功能&#xff0c;同时提高开发效…...

CentOS 7安装Docker详细教程

本文以 CentOS7.8 为例安装 Docker 26.1.4 、Docker Compose、以及 Docker 镜像仓库。 1.安装Docker社区版 1.1 安装准备 1.1.1 检查系统环境 Docker 不支持32位的 CentOS 7 系统&#xff0c;要求系统内核版本为3.10 以上&#xff0c;可以通过命令 uname -r 来查看当前系统…...

【Python】 -- 趣味代码 - 小恐龙游戏

文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...

7.4.分块查找

一.分块查找的算法思想&#xff1a; 1.实例&#xff1a; 以上述图片的顺序表为例&#xff0c; 该顺序表的数据元素从整体来看是乱序的&#xff0c;但如果把这些数据元素分成一块一块的小区间&#xff0c; 第一个区间[0,1]索引上的数据元素都是小于等于10的&#xff0c; 第二…...

Zustand 状态管理库:极简而强大的解决方案

Zustand 是一个轻量级、快速和可扩展的状态管理库&#xff0c;特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)

服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》

在注意力分散、内容高度同质化的时代&#xff0c;情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现&#xff0c;消费者对内容的“有感”程度&#xff0c;正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中&#xff0…...

MySQL中【正则表达式】用法

MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现&#xff08;两者等价&#xff09;&#xff0c;用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例&#xff1a; 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...

DeepSeek源码深度解析 × 华为仓颉语言编程精粹——从MoE架构到全场景开发生态

前言 在人工智能技术飞速发展的今天&#xff0c;深度学习与大模型技术已成为推动行业变革的核心驱动力&#xff0c;而高效、灵活的开发工具与编程语言则为技术创新提供了重要支撑。本书以两大前沿技术领域为核心&#xff0c;系统性地呈现了两部深度技术著作的精华&#xff1a;…...

面试高频问题

文章目录 &#x1f680; 消息队列核心技术揭秘&#xff1a;从入门到秒杀面试官1️⃣ Kafka为何能"吞云吐雾"&#xff1f;性能背后的秘密1.1 顺序写入与零拷贝&#xff1a;性能的双引擎1.2 分区并行&#xff1a;数据的"八车道高速公路"1.3 页缓存与批量处理…...

Unity VR/MR开发-VR开发与传统3D开发的差异

视频讲解链接&#xff1a;【XR马斯维】VR/MR开发与传统3D开发的差异【UnityVR/MR开发教程--入门】_哔哩哔哩_bilibili...

aardio 自动识别验证码输入

技术尝试 上周在发学习日志时有网友提议“在网页上识别验证码”&#xff0c;于是尝试整合图像识别与网页自动化技术&#xff0c;完成了这套模拟登录流程。核心思路是&#xff1a;截图验证码→OCR识别→自动填充表单→提交并验证结果。 代码在这里 import soImage; import we…...