【嵌入式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

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

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

相关文章

Junit4单元测试快速上手

文章目录 POM依赖引入业务层测试代码Web层测试代码生成测试类文件 在工作中我用的最多的单元测试框架是Junit4。通常在写DAO、Service、Web层代码的时候都会进行单元测试&#xff0c;方便后续编码&#xff0c;前端甩锅。 POM依赖引入 <dependency><groupId>org.spr…

【优选算法】查找总价格为目标值的两个商品(双指针)

算法_云边有个稻草人的博客-CSDN博客 目录 解法一&#xff1a;暴力算法 解法二&#xff1a;双指针(时间复杂度为O&#xff08;N&#xff09;) 【代码编写】 LCR 179. 查找总价格为目标值的两个商品 - 力扣&#xff08;LeetCode&#xff09; 解法一&#xff1a;暴力算法 用…

时空信息平台-API安全措施-下篇:登录鉴权【访问受限】您的请求已被该站点的安全策略拦截。

文章目录 引言I 登录鉴权处理逻辑校验顺序用户状态校验密码校验Token鉴权短信验证码/图形验证码登录设备限制II 服务端发生错误的处理业务返回码处理前端处理业务返回码nginx处理http状态码引言 时空信息平台-API安全措施:上篇(通讯协议的安全措施) https://blog.csdn.net/z…

编译openssl遇到错误Parse errors: No plan found in TAP output的解决方法

在编译openssl时 tar -zxvf openssl-1.1.1p.tar.gz cd openssl-1.1.1p ./config --prefix/usr --openssldir/etc/ssl --shared zlib make make test 遇到错误 Parse errors: No plan found in TAP output 解决方法&#xff1a; yum install perl-Test-Simple

【Linux】进度条

本文中&#xff0c;我们来写一个进度条。 本文大纲&#xff1a; 写一个命令行版的进度条。 1.回车换行 2.缓冲区问题&#xff08;本文不深究&#xff09; ​ 2.1测试代码 3.写一个什么样的进度条&#xff1f; ​ version1 ​ version2 回车换行 这俩不是一个概念&…

UE5材质节点SimpleGrassWind

SimpleGrassWind节点可以模拟树叶扰动&#xff0c;或小草晃动效果 用来做风格化树、风格化草效果很好 主要节点 前三个节点分别用来控制&#xff0c;风强度&#xff0c;风重力&#xff0c;风速度&#xff0c;WPO是世界位置偏移

WeNet:面向生产的流式和非流式端到端语音识别工具包

这篇文章介绍了WeNet&#xff0c;一个面向生产的开源端到端&#xff08;E2E&#xff09;语音识别工具包。WeNet的主要特点和贡献如下&#xff1a; 统一流式和非流式识别&#xff1a;提出了一种名为U2的两阶段框架&#xff0c;能够在单一模型中同时支持流式和非流式语音识别&…

Ubuntu20.04安装Foxit Reader 福昕阅读器

Ubuntu20.04安装Foxit Reader 福昕阅读器 文章目录 Ubuntu20.04安装Foxit Reader 福昕阅读器 先更新一下源 sudo apt update sudo apt upgrade下载Foxit Reader的稳定版本 wget https://cdn01.foxitsoftware.com/pub/foxit/reader/desktop/linux/2.x/2.4/en_us/FoxitReader.e…

2024年底关于期货的工作总结

十几年程序猿出身&#xff0c;因几年前的懵懂无畏闯入期货市场&#xff0c;盈了&#xff0c;感觉期货太简单&#xff0c;飘然裸辞&#xff0c;想当财务自由者&#xff0c;全职做交易。当深入学习时&#xff0c;却亏了&#xff0c;原来市场是让人敬畏的&#xff0c;也是反人性的…

PlantUML 时序图 基本例子

基本的例子 序列-> 用于绘制两个参与者之间的信息。参与者不必明确声明。 要有一个点状的箭头&#xff0c;就用--> 也可以用<- 和<-- 。这不会改变绘图&#xff0c;但可能提高可读性。注意&#xff0c;这只适用于顺序图&#xff0c;其他图的规则不同。 plantum…

vue3使用video-player实现视频播放(可拖动视频窗口、调整大小)

1.安装video-player npm install video.js videojs-player/vue --save在main.js中配置全局引入 // 导入视频播放组件 import VueVideoPlayer from videojs-player/vue import video.js/dist/video-js.cssconst app createApp(App) // 视频播放组件 app.use(VueVideoPlayer)2…

基于卷积神经网络的甲状腺结节识别系统,resnet50,mobilenet模型【pytorch框架+python源码】

更多目标检测、图像分类识别、目标追踪等项目可看我主页其他文章 功能演示&#xff1a; 甲状腺结节识别系统&#xff0c;卷积神经网络&#xff0c;resnet50&#xff0c;mobilenet【pytorch框架&#xff0c;python源码】_哔哩哔哩_bilibili &#xff08;一&#xff09;简介 …

C++--类与对象

1.封装 封装是c面向对象的三大特性之一 将属性和行为作为一个整体 将属性和行为加以权限控制 语法&#xff1a; class 类名{ 访问权限: 属性/行为 }; 访问权限 public 公共权限 类内类外均可以访问 protected 保护权限 类内可以访问&#xff0c;类外不可以访问 pr…

区块链期末复习3:跨链原子交换其他加密货币

参考教材&#xff1a;《区块链&#xff1a;技术驱动金融》 一、跨链原子交换&#xff08;不可分割的交叉链互换&#xff09; 1.实施步骤 假设Alice要拿1BTC交换Bob的3BCY。Alice作为交易的发起者。 1&#xff09;Alice创建一个secret&#xff08;一个随机数x), 并计算其哈希…

OCR实践-Table-Transformer

前言 书接上文 OCR实践—PaddleOCR Table-Transformer 与 PubTables-1M table-transformer&#xff0c;来自微软&#xff0c;基于Detr&#xff0c;在PubTables1M 数据集上进行训练&#xff0c;模型是在提出数据集同时的工作&#xff0c; paper PubTables-1M: Towards comp…

重装操作系统后 Oracle 11g 数据库数据还原

场景描述&#xff1a; 由于SSD系统盘损坏&#xff0c;更换硬盘后重装了操作系统&#xff0c;Oracle数据库之前安装在D盘(另一个硬盘)&#xff0c;更换硬盘多添加一个盘符重装系统后盘符从D变成E&#xff0c;也就是之前的D:/app/... 变成了现在的 E:/app/...&#xff0c;重新安装…

gozero项目接入elk的配置与实战

在 **GoZero** 项目中接入 **ELK&#xff08;Elasticsearch、Logstash、Kibana&#xff09;** 来进行日志管理&#xff0c;是一个非常强大的监控和分析方案。通过集成 ELK&#xff0c;你可以收集、存储、查询和可视化日志数据。 在这里&#xff0c;我将介绍如何在 GoZero 项目中…

探索PIL库:Python图像处理的强大工具

文章一览 前言一、PIL图像处理库简介二、基本概念2.1颜色模型2.1.1 RGB 颜色模型2.1.2 CMY色彩空间 2.2 通道2.3 图像数据2.4 模式 三、用PIL做图像处理3.1 图像缩放、翻转等处理3.1.1 图像缩放处理3.1.2 图像旋转处理&#xff08;1&#xff09;PIL 提供的函数:&#xff08;2&a…

微信V3支付报错 平台证书及平台证书序列号

1.平台证书及平台证书序列号设置错误报错&#xff1a; 错误1&#xff1a; Verify the response’s data with: timestamp1735184656, noncea5806b8cabc923299f8db1a174f3a4d0, signatureFZ5FgD/jtt4J99GKssKWKA/0buBSOAbWcu6H52l2UqqaJKvrsNxvodB569ZFz5G3fbassOQcSh5BFq6hvE…

【Python科研数据爬虫】基于国家标准查询平台和能源标准化信息平台的海上风电相关行业标准查询信息爬取及处理

基于国家标准查询平台和能源标准化信息平台的海上风电相关行业标准查询信息爬取及处理 1 背景2 标准检索平台2.1 能源标准化信息平台2.2 全国标准信息公共服务平台3 标准信息数据的爬取与处理3.1 能源标准化信息平台的信息爬取3.2 全国标准信息公共服务平台的信息爬取3.3 标准信…