【C语言】自定义类型:结构体

1. 结构体类型的声明

1.1 结构体回顾

结构是⼀些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。

1.1.1 结构的声明

struct tag
{member-list;
}variable-list;
例如描述⼀个学⽣:
struct Stu
{char name[20];//名字int age;//年龄char sex[5];//性别char id[20];//学号
}; //分号不能丢

1.1.2 结构体变量的创建和初始化

#include <stdio.h>
struct Stu
{char name[20];//名字int age;//年龄char sex[5];//性别char id[20];//学号
};int main()
{//按照结构体成员的顺序初始化struct Stu s = { "张三", 20, "男", "20240218001" };printf("name: %s\n", s.name);printf("age : %d\n", s.age);printf("sex : %s\n", s.sex);printf("id : %s\n", s.id);//按照指定的顺序初始化struct Stu s2 = { .age = 18, .name = "lisi", .id = "20240218002", .sex = "女" };printf("name: %s\n", s2.name);printf("age : %d\n", s2.age);printf("sex : %s\n", s2.sex);printf("id : %s\n", s2.id);return 0;
}

运行结果:

1.2 结构的特殊声明

在声明结构的时候,可以不完全的声明。
⽐如:
//匿名结构体类型
struct
{int a;char b;float c;
}x;
struct
{int a;char b;float c;
}a[20], *p;
上⾯的两个结构在声明的时候省略掉了结构体标签(tag)。
那么问题来了?
//在上⾯代码的基础上,下⾯的代码合法吗?
p = &x;
警告:
编译器会把上⾯的两个声明当成完全不同的两个类型,所以是⾮法的。
匿名的结构体类型,如果没有对结构体类型重命名的话,基本上只能使⽤⼀次。

1.3 结构的自引用

在结构中包含⼀个类型为该结构本⾝的成员是否可以呢?

⽐如,定义⼀个链表的节点:
struct Node
{int data;struct Node next;
};
上述代码正确吗?如果正确,那 sizeof(struct Node) 是多少?
仔细分析,其实是不⾏的,因为⼀个结构体中再包含⼀个同类型的结构体变量,这样结构体变量的⼤⼩就会⽆穷的⼤,是不合理的。
正确的⾃引⽤⽅式:
struct Node
{int data;struct Node* next;
};
在结构体⾃引⽤使⽤的过程中,夹杂了 typedef 对匿名结构体类型重命名,也容易引⼊问题,看看
下⾯的代码,可⾏吗?
typedef struct
{int data;Node* next;
}Node;
答案是不⾏的,因为Node是对前⾯的匿名结构体类型的重命名产⽣的,但是在匿名结构体内部提前使⽤Node类型来创建成员变量,这是不⾏的。
解决方案如下:定义结构体不要使用匿名结构体了
typedef struct Node
{int data;struct Node* next;
}Node;

2. 结构体内存对齐

我们已经掌握了结构体的基本使⽤了。
现在我们深⼊讨论⼀个问题:计算结构体的⼤⼩。

2.1 对齐规则

⾸先得掌握结构体的对⻬规则:
1. 结构体的第⼀个成员对⻬到和结构体变量起始位置偏移量为0的地址处
2. 其他成员变量要对⻬到某个数字(对⻬数)的整数倍的地址处。
对⻬数 = 编译器默认的⼀个对⻬数 与 该成员变量⼤⼩的较⼩值
- VS 中默认的值为 8
- Linux中 gcc 没有默认对⻬数,对⻬数就是成员⾃⾝的⼤⼩
3. 结构体总⼤⼩为最⼤对⻬数(结构体中每个成员变量都有⼀个对⻬数,所有对⻬数中最⼤的)的
整数倍。
4. 如果嵌套了结构体的情况,嵌套的结构体成员对⻬到⾃⼰的成员中最⼤对⻬数的整数倍处,结构
体的整体⼤⼩就是所有最⼤对⻬数(含嵌套结构体中成员的对⻬数)的整数倍。
//练习1
struct S1
{char c1;int i;char c2;
};
printf("%d\n", sizeof(struct S1));
//练习2
struct S2
{char c1;char c2;int i;
};
printf("%d\n", sizeof(struct S2));//练习3
struct S3
{double d;char c;int i;
};
printf("%d\n", sizeof(struct S3));
//练习4-结构体嵌套问题
struct S4
{char c1;struct S3 s3;double d;
};
printf("%d\n", sizeof(struct S4));

2.2 为什么存在内存对⻬?

⼤部分的参考资料都是这样说的:
1. 平台原因 (移植原因):
不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2. 性能原因:
数据结构(尤其是栈)应该尽可能地在⾃然边界上对⻬。原因在于,为了访问未对⻬的内存,处理器需要作两次内存访问;⽽对⻬的内存访问仅需要⼀次访问。假设⼀个处理器总是从内存中取8个字节,则地 址必须是8的倍数。如果我们能保证将所有的double类型的数据的地址都对⻬成8的倍数,那么就可以⽤⼀个内存操作来读或者写值了。否则,我们可能需要执⾏两次内存访问,因为对象可能被分放在两个8字节内存块中。
总体来说:结构体的内存对⻬是拿空间来换取时间的做法。
那在设计结构体的时候,我们既要满⾜对⻬,⼜要节省空间,如何做到:
让占⽤空间⼩的成员尽量集中在⼀起
//例如:struct S1{char c1;int i;char c2;};struct S2{char c1;char c2;int i;};
S1 S2 类型的成员⼀模⼀样,但是 S1 S2 所占空间的⼤⼩有了⼀些区别。

2.3 修改默认对齐数

#pragma 这个预处理指令,可以改变编译器的默认对⻬数。
#include <stdio.h>
#pragma pack(1)//设置默认对⻬数为1
struct S
{char c1;int i;char c2;
};
#pragma pack()//取消设置的对⻬数,还原为默认
int main()
{//输出的结果是什么?printf("%d\n", sizeof(struct S));return 0;
}

运行结果:

结构体在对⻬⽅式不合适的时候,我们可以⾃⼰更改默认对⻬数。

3. 结构体传参

#include <stdio.h>struct S
{int data[1000];int num;
};
struct S s = { {1,2,3,4}, 1000 };
//结构体传参
void print1(struct S s)
{printf("%d\n", s.num);
}
//结构体地址传参
void print2(struct S* ps)
{printf("%d\n", ps->num);
}
int main()
{print1(s); //传结构体print2(&s); //传地址return 0;
}

运行结果:

上⾯的 print1 print2 函数哪个好些?
答案是:⾸选print2函数

原因:

函数传参的时候,参数是需要压栈,会有时间和空间上的系统开销。
如果传递⼀个结构体对象的时候,结构体过⼤,参数压栈的的系统开销⽐较⼤,所以会导致性能的下降。
结论:
结构体传参的时候,要传结构体的地址。

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

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

相关文章

Vue前端项目安装及相关问题解决

目录 安装 以人人开源前端项目安装为例&#xff0c;安装部署及安装过程中的问题的解决思路。开源地址如下&#xff1a; 人人开源 下载代码到本地 安装visial studio code&#xff08;即VSCode&#xff09;作为前端开发工具&#xff0c;使用前端前必须安装node.js作为让js运行…

Android 生成SO - 基础工程创建

最近需要给小伙伴扫盲一下如何使用Android Studio 生成一个SO文件&#xff0c;网上找了很多都没有合适的样例&#xff0c;那只能自己来写一个了。 原先生成SO是一个很麻烦的事情&#xff0c;现在Android Studio帮忙做了很多的事情&#xff0c;基本只要管好自己的C代码即可。 …

【梳理】k8s使用Operator搭建Flink集群(高可用可选)

文章目录 1. 架构图2. helm 安装operator3. 集群知识k8s上的两种模式&#xff1a;Native和Standalone两种CR 4. 运行集群实例Demo1&#xff1a;Application 集群Demo2&#xff1a;Session集群优劣 5. 高可用部署问题1&#xff1a;High availability should be enabled when sta…

3.1_2 覆盖与交换

3.1_2 覆盖与交换 &#xff08;一&#xff09;覆盖技术 早期的计算机内存很小&#xff0c;比如IBM 推出的第一台PC机最大只支持1MB大小的内存。因此经常会出现内存大小不够的情况。 后来人们引入了覆盖技术&#xff0c;用来解决“程序大小超过物理内存总和”的问题。 覆盖技术的…

DevOps-Jenkins-CI持续集成操作

创建项目 创建个web项目 我这里直接用Spring Web自动生成的demos 启动项目&#xff0c;访问展示如下默认页面信息 项目新增Docker构建配置 在项目下新建docker目录&#xff0c;新增Dockerfile、docker-compose.yml文件 Dockerfile文件&#xff0c;将mytest.jar 复制到容器的…

移动硬盘无法读取怎么修复?分享三个简单方法

移动硬盘作为现代数据存储的重要工具&#xff0c;一旦出现故障&#xff0c;往往会让我们感到焦虑和困惑。当移动硬盘无法读取时&#xff0c;我们需要冷静分析并采取适当的措施来修复它。本文将为您介绍三种有效的修复方法。 一、检查物理连接与驱动程序 当移动硬盘无法读取时&…

LiveGBS流媒体服务器中海康摄像头GB28181公网语音对讲、语音喊话的配置

LiveGBS海康摄像头国标语音对讲大华摄像头国标语音对讲GB28181语音对讲需要的设备及服务准备 1、背景2、准备2.1、服务端必备条件&#xff08;注意&#xff09;2.2、准备语音对讲设备2.2.1、不支持跨网对讲示例2.2.2、 支持跨网对讲示例 3、开启音频开始对讲4、搭建GB28181视频…

动手学深度学习-注意力机制Transformer

注意力机制 1. 注意力提示 1.1. 生物学中的注意力提示 **自主性提示&#xff08;随意线索&#xff09;&#xff1a;收到认知和意识的控制&#xff0c;有主观意愿的推动。**如下图&#xff0c;所有纸制品都是黑白印刷的&#xff0c;但咖啡杯是红色的。 换句话说&#xff0c;这…

【办公类-21-09】三级育婴师 视频转文字docx(等线小五单倍行距),批量改成“宋体小四、1.5倍行距、蓝色字体”

作品展示&#xff1a; 背景需求&#xff1a; 一、视频处理 1、育婴师培训的现场视频 2、下载视频&#xff0c;将视频换成考题名称 二、音频 视频用格式工厂转成MP3音频 3、转文字doc 把音频放入“网易云见外工作台”转换为“文字" 等待5分钟&#xff0c;音频文字会被写…

Python元组(Tuple)深度解析!

目录 1. 什么是元组&#xff1f; 2. 创建元组 3.访问元组 4.元组的运算 5.修改元组不可行 6.元组的应用场景 前面的博客里&#xff0c;我们详细介绍了列表&#xff08;List&#xff09;这一种数据类型&#xff0c;现在我们来讲讲与列表相似的一种数据类型&#xff0c;元组…

【Python】【Matplotlib】fig, ax = plt.subplots() 返回的fig和ax是什么?

【Python】【Matplotlib】fig, ax plt.subplots() 返回的fig和ax是什么&#xff1f; &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程&a…

求职干货!如何自信地进行自我介绍和面试问答!

面试在求职过程中扮演着至关重要的角色。它不仅是雇主评估候选人能力和适应性的关键环节&#xff0c;也是候选人展示自我、展示技能和经验的绝佳机会。通过面试&#xff0c;雇主可以更直接地了解候选人的沟通能力、解决问题的能力以及团队合作精神&#xff0c;这些都是成功工作…

ChatGPT GPT4科研应用、数据分析与机器学习、论文高效写作、AI绘图技术

原文链接&#xff1a;ChatGPT GPT4科研应用、数据分析与机器学习、论文高效写作、AI绘图技术https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247596849&idx3&sn111d68286f9752008bca95a5ec575bb3&chksmfa823ad6cdf5b3c0c446eceb5cf29cccc3161d746bdd9f2…

实例成员、静态成员

一、静态成员先于实例成员存在 类被加载到内存时&#xff0c;静态变量分配内存空间&#xff0c;静态方法分配入口地址 只有创建对象之后&#xff0c;实例变量分配内存空间&#xff0c;实例方法分配入口地址 当再创建对象时&#xff0c;实例方法不再分配入口地址&#xff0c;…

【Java从发入门到精通】Java StringBuffer 和 StringBuilder 类

Java StringBuffer 和 StringBuilder 类 当对字符串进行修改的时候&#xff0c;需要使用 StringBuffer 和 StringBuilder 类。 和 String 类不同的是&#xff0c;StringBuffer 和 StringBuilder 类的对象能够被多次的修改&#xff0c;并且不产生新的未使用对象。 在使用 Stri…

蓝桥杯[OJ 3412]-最小化战斗力差距-CPP-贪心

目录 一、问题描述&#xff1a; 二、整体思路&#xff1a; 三、代码&#xff1a; 一、问题描述&#xff1a; 二、整体思路&#xff1a; 首先每个值都有可能为min(b)&#xff0c;那么对于每个可能为min(b)的值&#xff0c;要使得max(a)尽可能小&#xff0c;因此枚举所有相差最…

高颜值抓包工具Charles,实现Mac和IOS端抓取https请求

Hi&#xff0c;大家好。在进行测试的过程中&#xff0c;不可避免的会有程序报错&#xff0c;为了能更快修复掉Bug&#xff0c;我们作为测试人员需要给开发人员提供更准确的报错信息或者接口地址&#xff0c;这个时候就需要用到我们的抓包工具。 常见的抓包工具有Fiddler、Char…

【NR技术】 3GPP支持无人机服务的关键性能指标

1 性能指标概述 5G系统传输的数据包括安装在无人机上的硬件设备(如摄像头)收集的数据&#xff0c;例如图片、视频和文件。也可以传输一些软件计算或统计数据&#xff0c;例如无人机管理数据。5G系统传输的业务控制数据可基于应用触发&#xff0c;如无人机上设备的开关、旋转、升…

Oracle之ADG与DG的区别?

在上云后的Oracle数据灾备场景中&#xff0c;我们经常听到DBA迁移工程师讲到“在这个项目中用ADG进行数据实时备份&#xff0c;ADG比DG更好&#xff01;”。究竟ADG作Oracle数据灾备的优势在什么地方&#xff1f; 一、ADG主要解决了DG时代读写不能并行的问题 DG时代的数据同步…

c# winform部门管理系统

c# winform部门管理系统 数据库SQL语句脚本代码 CREATE TABLE Department(DepartmentID INT PRIMARY KEY IDENTITY(1,1),Name NVARCHAR(50) NOT NULL ); SELECT * FROM Department -- 插入部门数据 INSERT INTO Department (Name) VALUES (人力资源部); INSERT INTO Departmen…