重头开始嵌入式第十六天(结构体,共用体)

news2024/9/21 2:47:55

目录

结构体

结构体定义

结构体初始化

结构体赋值

结构体调用

结构体大小

在 C 语言中,结构体内存对齐规则主要遵循以下原则:

共用体

共用体定义

共同体赋值,初始化

 共用体大小

结构体与共用体的区别


结构体

在 C 语言中,结构体(struct)是一种用户自定义的数据类型,用于将不同类型的数据组合在一起,形成一个逻辑上相关的整体。
 
 
 

结构体定义

结构体的定义格式如下:

struct 结构体名 {
    数据类型 成员名 1;
    数据类型 成员名 2;
    // 可以有多个成员
  ...
};
 
 
例如:
 

struct Student {
    int id;
    char name[50];
    float score;
};


在定义结构体变量时,可以采用以下方式:

struct Student stu1; 


或者

struct Student stu2 = {101, "Alice", 90.5}; 


要访问结构体成员,可以使用“.”操作符,例如:

stu1.id = 102;
printf("%s\n", stu2.name);


 
结构体在 C 语言中应用广泛,常用于组织和处理复杂的数据结构,如链表、树等。

 
关键知识点展开讲解:


- 结构体成员的数据类型可以是基本数据类型(如 int、float、char 等),也可以是其他自定义的数据类型,包括指针、数组等。
- 结构体可以嵌套,即在一个结构体中包含另一个结构体作为成员。
- 结构体变量在内存中的存储是按照成员的顺序依次排列的,每个成员按照其自身的数据类型所占用的字节数进行存储。

结构体初始化



有两种常见的初始化方式。
 
1. 直接在定义结构体变量时进行初始化:

struct Student {
    int id;
    char name[50];
    float score;
} stu1 = {101, "Alice", 90.5};


 
2. 先定义结构体变量,然后再分别对成员进行赋值:

struct Student stu2;
stu2.id = 102;
strcpy(stu2.name, "Bob");
stu2.score = 85.0;


结构体赋值


可以通过逐个成员赋值,或者将一个结构体变量的值赋给另一个同类型的结构体变量。

struct Student stu3;
stu3 = stu2;  // 结构体变量之间的赋值


结构体调用


 
通过“.”操作符来访问结构体成员。

printf("Student ID: %d\n", stu1.id);
printf("Student Name: %s\n", stu1.name);
printf("Student Score: %.2f\n", stu1.score);


 在 C 语言中,结构体指针用于操作结构体变量。以下是关于结构体指针的一些常见操作:

定义结构体指针:

struct Student {

    int id;

    char name[50];

    float score;

};



struct Student *ptr; // 定义一个指向 struct Student 类型的指针

通过指针访问结构体成员:

有两种方式,使用“->”操作符或者先解引用指针再使用“.”操作符。

ptr = &stu; // 假设 stu 是已定义的 struct Student 类型变量



// 方式一:使用 "->" 操作符

ptr->id = 101;

printf("%s\n", ptr->name);



// 方式二:先解引用再使用 "." 操作符

(*ptr).id = 102;

printf("%f\n", (*ptr).score);

动态分配结构体内存:

ptr = (struct Student *)malloc(sizeof(struct Student));

if (ptr == NULL) {

    printf("Memory allocation failed!\n");

    return 1;

}



ptr->id = 200;

strcpy(ptr->name, "Tom");

ptr->score = 95.5;



free(ptr); // 使用完后释放内存

结构体指针在处理复杂的数据结构、传递结构体参数给函数等场景中非常有用,能够提高程序的灵活性和效率。


结构体大小


结构体的大小等于其所有成员大小之和。但是由于内存对齐的原因,实际占用的内存空间可能会大于各成员大小之和。内存对齐是为了提高 CPU 访问内存的效率。
 
可以使用  sizeof  运算符来获取结构体的大小。
 

printf("Size of Student struct: %zu\n", sizeof(struct Student));


 
需要注意的是,不同的编译器和平台可能会有不同的内存对齐规则,导致结构体大小有所差异。

在 C 语言中,结构体内存对齐规则主要遵循以下原则:

1. 结构体的每个成员按照其自身的数据类型进行对齐。通常,基本数据类型的对齐值等于其自身的大小。例如, char  类型的对齐值为 1 字节, int  类型通常为 4 字节(在 32 位系统中)。
2. 结构体的总大小必须是其最大成员大小的整数倍。
3. 结构体成员的存放起始地址是其对齐值的整数倍。如果当前位置不满足对齐要求,会进行填充空白字节以满足对齐。
例如,对于以下结构体:
struct example {
    char a; // 1 字节
    int b; // 4 字节
    short c; // 2 字节
};
为了满足  int  类型的 4 字节对齐, char  类型的成员  a  之后可能会填充 3 个字节,然后存放  int  类型的成员  b  。接着, short  类型的成员  c  会按照 2 字节对齐存放。
内存对齐的主要目的是提高 CPU 访问内存的效率,尤其是在现代计算机体系结构中。
不同的编译器可能会有略微不同的内存对齐实现方式,但总体原则是相似的。

共用体

在 C 语言中,共用体(Union)是一种特殊的数据类型,它使得多个不同类型的变量共享同一段内存空间。
 

共用体定义


共用体的定义格式如下:

union 共用体名 {
    数据类型 成员名 1;
    数据类型 成员名 2;
    // 可以有多个成员
 ...
};
 
 
例如:
 

union Data {
    int i;
    float f;
    char str[20];
};

共同体赋值,初始化

以下是关于共用体赋值和初始化的示例及相关说明:
 
初始化共用体:
 
可以在定义共用体变量时进行初始化,方式类似于结构体的初始化。

union Data data1 = {.i = 10};  // 初始化共用体的成员 i 为 10


 
或者

union Data data2 = {20.5f};  // 初始化共用体的成员 f 为 20.5


赋值共用体:
 
在共用体中赋值会覆盖之前存储的其他成员的值。

union Data data;
data.i = 5;  // 给成员 i 赋值
data.f = 3.14f;  // 此时成员 i 的值被覆盖,存储了成员 f 的值
 


 
需要注意的是,由于共用体的所有成员共享同一块内存空间,所以在使用共用体时要特别小心,确保对其的操作符合预期,避免因成员值的覆盖而导致数据混乱或错误。


 共用体大小


在共用体中,同一时刻只能存储其中一个成员的值。共用体的大小取决于其最大成员的大小。
 
关键知识点展开讲解:
 
- 由于共用体的所有成员共享同一段内存,所以对一个成员的赋值会覆盖其他成员的值。
- 共用体常用于节省内存空间或者在不同时刻需要使用不同类型的数据的场景。
 
例如,在处理不同格式的数据时,如果在某个时刻只需要使用其中一种格式的数据,就可以使用共用体来节省内存。

结构体与共用体的区别

结构体和共用体主要有以下区别:

1. 内存分配:

- 结构体:结构体的每个成员都有自己独立的内存空间,结构体的总内存大小是所有成员内存大小之和。

- 共用体:共用体的所有成员共享同一块内存空间,内存大小等于其最大成员的内存大小。

2. 存储方式:

- 结构体:可以同时存储所有成员的值。

- 共用体:同一时刻只能存储一个成员的值。

3. 用途:

- 结构体:适用于需要将不同类型但相关的数据组合在一起,并且需要同时访问和处理这些数据的情况。

- 共用体:常用于节省内存或者在不同时刻需要使用不同类型的数据的场景。

4. 数据完整性:

- 结构体:能保证各个成员数据的完整性和独立性。

- 共用体:由于成员值的相互覆盖,可能导致数据的不确定性和不完整性。

总之,结构体强调的是数据的组合和完整性,而共用体更侧重于内存的高效利用和灵活的数据类型切换。

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

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

相关文章

vuex properties of undefined (reading ‘getters‘)

前言: 最近打算用vue 写个音乐播放器,在搞 vuex 的时候遇到一个很神奇报错;vuex 姿势练了千百次了,刚开始的时候我一直以为是代码问题,反复检查了带了,依旧报错。 Error in mounted hook: "TypeError:…

PHP全方位多功能投票小程序系统源码

🌟【全民参与,决策更精彩】全方位多功能投票小程序大揭秘!🎉 🚀 开篇引入:投票新风尚,尽在指尖 Hey小伙伴们,你是否厌倦了传统的投票方式,觉得它们既繁琐又不够灵活&am…

历代文学-技术生态-总体介绍

1. 历代文学简介 历代文学(https://literature.sinhy.com/#/literature?__c1000,微信小程序可直接搜索“历代文学”)是一个由两个人(一个后端和一个前端)开发的文学网站,是一个收录从古到今、以及古今中外…

C++之运算符重载系列深入学习:从入门到精通!

为什么需要对运算符进行重载 C预定义中的运算符的操作对象只局限于基本的内置数据类型,但是对于我们自定义的类型是没有办法操作的。但是大多时候我们需要对我们定义的类型进行类似的运算,这个时候就需要我们对这么运算符进行重新定义,赋予其…

智能家居中高性能联网通信方案,乐鑫ESP32-S3/C3无线Wi-Fi蓝牙应用

随着科技的飞速发展,智能家居已经不再是科幻小说中的概念,而是走进了千家万户的现实生活。 智能家居是广泛的系统性产品概念,以住宅为载体,运用物联网、网络通信和人工智能等技术,接收信号并判断,提供更加…

美股全线反弹,市场情绪回暖

一、市场概况 昨夜美股三大股指全线收涨,市场情绪明显回暖。道琼斯工业平均指数上涨1.76%,纳斯达克综合指数上涨2.87%,标普500指数则上涨2.3%。美债市场方面,美国十年期国债收益率上涨1.141%,报3.99%,两年…

[ Python ]使用Charles对Python程序发出的Get与Post请求抓包-解决Python程序报错问题

目录 一、前言 二、Charles 三、抓取Python请求 3.1 正常运行 3.2 程序报错 3.2.1 报错信息 3.2.2 解决方法 3.3 取消警告信息 四、总结 一、前言 在Python开发中,网络请求是常见的操作之一。无论是使用内置的urllib库还是第三方库requests,都可…

Java小白入门到实战应用教程-Scanner类及IO流讲解

Java小白入门到实战应用教程-Scanner类及IO流讲解 Scanner类 我们前面写的很多例子都是程序独自执行的,但是我们做编程写代码的目的是要实现能人和代码去交互的。 现在我们就来了解一个知识点,去实现最简单的人和程序的交互。 在java中通过Scanner类…

MySQL第3讲--数据类型和表的修改和删除

文章目录 前言数据类型数值类型整数类型浮点数和定点数 字符串类型字符类型:文本类型:二进制数据类型 日期和时间类型实例分析 表的操作添加字段修改字段删除字段修改表名删除表 DDL总结DDL数据库操作DDL表操作 前言 上一节在MySQL第2讲–关系型数据库以…

kubernetes 管理平台 Pod管理多容器 与嵌入式脚本

资源清单文件 模板与帮助信息 管理资源对象 多容器 Pod 管理多容器 Pod 自定义任务 容器保护策略 宽限期策略 Pod调度策略

CUDA编程从零到壹

如今,当我们谈论深度学习时,为了提高性能,我们通常会将其实现与使用 GPU 联系起来。 GPU(图形处理单元)最初设计用于加速图像、2D 和 3D 图形的渲染。然而,由于它们能够执行许多并行操作,它们的…

linux 源码部署polardb-x 错误汇总

前言 在linux 源码部署polardb-x 遇到不少错误,特在此做个汇总。 问题列表 CN 启动报错 Failed to init new TCP 详细错误如下 Caused by: Failed to init new TCP. XClientPool to my_polarx#267b21d8127.0.0.1:33660 now 0 TCP(0 aging), 0 sessions(0 runni…

【汇总】测开高频面试题

加油 !!! 🔥 谈谈对测试的理解 我认为测试是发现并及时解决问题:包括功能、性能、用户体验❤️等方面的验证 … 通过提前定位并修复缺陷,可以减少未来维护成本、保障软件质量、提升用户满意度❤️ … 我了…

大麦/猫眼抢票-狠货

大部分购买方式已迁移至手机端,专注研究移动端 小白操作–仅供学习 注意在帐号按权重的第三方账号设置解绑淘宝,否则有可能在抢票时候出现滑块,影响抢票,抢票优先选择大麦 ⚠️核心内容参考: 据悉,在购票环节&…

23_windows 使用sqlmap、kali使用sqlmap,SQL注入、sqlmap自动注入

sqlmap介绍 安装sqlmap 安装python环境 链接:https://pan.baidu.com/s/16QhhYCppSvuUikhKiOHNgg?pwd9LJY 提取码:9LJY C:\Users\leyilea> python // 测试python能不能用 >>> exit() // 退出 测试sqlmap是否可用 kali中运行sqlmap&#xff…

KAN网络简明教程

在不断发展的机器学习领域,最近一篇题为“KAN:柯尔莫哥洛夫-阿诺德网络”的研究论文在爱好者中引发了一波热潮。这种创新方法挑战了多层感知器 (MLP) 的传统观点,为神经网络架构提供了全新的视角。 NSDT工具推荐: Three.js AI纹理…

Qt 实战(9)窗体 | 9.2、QDialog

文章目录 一、QDialog1、基本概念2、常用特性2.1、模态与非模态2.2、数据交互 3、总结 前言: Qt框架中的QDialog类是一个功能强大且灵活的对话框控件,广泛应用于各种GUI(图形用户界面)应用程序中,用于处理用户输入、消…

map/multimap容器

一、 map基本概念 简介: map中所有元素都是pair pair中第一个元素为key(键值),起到索引惟用,第二个元素为value(实值) 所有元素都会根据元素的键值自动排序 本质: map/multimap属于关联式容器,底层结构是用二叉树实现 优点: 可以根据ke…

欧拉系统离线安装界面ukui

1、官网下载安装镜像iso后,默认没有gui openEuler | 开源社区 | openEuler社区官网openEuler是一个开源、免费的 Linux 发行版平台,将通过开放的社区形式与全球的开发者共同构建一个开放、多元和架构包容的软件生态体系。同时,openEuler 也是…

数据结构与算法|算法总结|动态规划篇之子序列、子数组问题

首先我们要明确以下两个问题: 子序列:子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。 子数组:子数组是数…