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

深度剖析 —— 结构体

系列文章目录

深度剖析:数据
深度剖析:递归
深度剖析:结构体
深度剖析:动态内存管理
深度剖析:文件操作
深度剖析:预处理


文章目录

  • 系列文章目录
  • 前言
  • 一、示例问题:创建通讯录
    • 1.通讯录的需求
  • 二、结构体
    • 1.建立结构声明
    • 2.创建结构变量
    • 3.初始化结构体
    • 4.访问结构成员
  • 三、结构体数组
    • 1.创建结构数组
    • 2.数组的初始化
    • 3.数组访问成员
  • 四、嵌套结构
    • 1.结构体的嵌套
    • 2.嵌套的初始化
    • 3.嵌套访问成员
  • 五、结构体指针
    • 1.创建结构指针
    • 2.指针的初始化
    • 3.指针访问成员
  • 六、结构体的计算
    • 1.空间换取时间
    • 2.结构体的存储
  • 总结

前言

在设计程序时,最重要的步骤之一是选择表示数据的方法。许多情况下数组已经部能很好的满足我们的需求,而结构变量通过创造新的形式提高了我们表示数据的能力。


一、示例问题:创建通讯录

1.通讯录的需求

通讯录就需要一种能包含数字的数据形式,而切要保持各信息的独立

信息

  1. 名字
  2. 年龄
  3. 性别
  4. 电话
  5. 地址

功能

  1. 增加
  2. 删除
  3. 查找
  4. 修改
  5. 排序

二、结构体

1.建立结构声明

结构声明(structure declaration)描述了一个结构组织布局

structPeoInfo{charName[8];charSex[4];intAge;charTelephone[12];charAddress[12];};

该声明描述了一个由四个字符数组和一个整型变量组成的结构。该声明并未创建实际的数据,只是描述了该对象由什么组成。
从本质上看,结构声明创建了一个名为struct PeoInfo的新类型(int double等类型等价) 。

struct

  1. 它表明其后的是一个结构
  2. struct PeoInfo则是这个结构的名称

2.创建结构变量

结构变量定义了一个struct PeoInfo类型的变量

structPeoInfoMail;

此时此刻才向堆栈申请了一块sizeof(struct PeoInfo)大小的空间(这里是为了便于理解所以恰好设置了40个字节的大小布局,后面会有结构体大小的计算详解)。

3.初始化结构体

struct PeoInfo类型也可以直接进行初始化

structPeoInfoMail={"小明","男",18,"11111111111","某小区"};

struct PeoInfoint等其他类型一样,可以直接进行赋值,它的内容需要由花括号括起来,各初始化项由逗号进行分隔。

4.访问结构成员

结构体成员的基本访问(对象.访问成员指针->访问成员)

printf("%s",Mail.Name);printf("%s",Mail.Sex);printf("%d",Mail.Age);printf("%s",Mail.Telephone);printf("%s",Mail.Address);

本质上Name、Sex、Age、Telephone、Address都是struct PeoInfo的下标,就像数组的下标0、1、2、3一样,数组是用[ ]来访问所在下标位置的元素, 而结构体则是用.->来访问成员。

三、结构体数组

1.创建结构数组

创建结构数组创建明其他类型的数组类似

structPeoInfoMail[100];

与其他类型一样,数组的每一个元素又是struct PeoInfo类型的元素。

2.数组的初始化

与其他数组一样只能在创建的时被直接初始化

structPeoInfoMail[20]={{"小明","男",18,"11111111111","某小区"},{"小红","女",18,"11111111111","某小区"}};

下面的这种写法是错误的!

Mail[0]={"小明","男",18,"11111111111","某小区"};//错误示例

3.数组访问成员

找到结构数组的某一个元素的下标进行访问

printf("%s",Mail[0].Name);printf("%s",Mail[0].Sex);printf("%d",Mail[0].Age);printf("%s",Mail[0].Telephone);printf("%s",Mail[0].Address);

四、嵌套结构

1.结构体的嵌套

当我们需求更丰富时就需要在结构体中嵌套一层结构体

//成员信息structPeoInfo{charName[8];charSex[4];intAge;charTelephone[11];charAddress[13];};//通讯录structContact{structPeoInfoData[MAX];//存放增加进来的人的信息(此处为结构体的嵌套)intcount;//记录当前通讯录中有效信息的个数}Contact;

2.嵌套的初始化

嵌套式结构体建议一个一个进行赋值而非直接初始化

//方法一strcpy(Mail.Data[0].Name,"小明");strcpy(Mail.Data[0].Sex,"男");Mail.Data[0].Age=18;strcpy(Mail.Data[0].Telephone,"11111111111");strcpy(Mail.Data[0].Address,"某小区");//方法二scanf("%s",Mail.Data[0].Name);scanf("%s",Mail.Data[0].Sex);scanf("%d",&Mail.Data[0].Age);scanf("%s",Mail.Data[0].Telephone);scanf("%s",Mail.Data[0].Address);

当结构体过于复杂时,不建议像下面代码这样直接初始化,当嵌套更加复杂时,直接初始化会非常困难。

structContactMail={{{"小明","男",18,"11111111111","某小区"},{"小红","女",18,"11111111111","某小区"}},20};

3.嵌套访问成员

嵌套成员依然是一层一层的去访问(与前面一模一样)

printf("%s",Mail.Data[0].Name);printf("%s",Mail.Data[0].Sex);printf("%d",Mail.Data[0].Age);printf("%s",Mail.Data[0].Telephone);printf("%s",Mail.Data[0].Address);

五、结构体指针

1.创建结构指针

指向结构体的指针

structContact*PMail;

2.指针的初始化

当结构体过于复杂时建议一个一个进行赋值

//方法一 (结构体过于复杂时不推荐该方法)structContactMail={{{"小明","男",18,"11111111111","某某小区"},{"小红","女",18,"11111111111","某某小区"}},20};structContact*PMail=&Mail;//方法二strcpy(PMail->Data[0].Name,"小明");strcpy(PMail->Data[0].Sex,"男");PMail->Data[0].Age=18;strcpy(PMail->Data[0].Telephone,"11111111111");strcpy(PMail->Data[0].Address,"某小区");//方法三scanf("%s",PMail->Data[0].Name);scanf("%s",PMail->Data[0].Sex);scanf("%d",&PMail->Data[0].Age);scanf("%s",PMail->Data[0].Telephone);scanf("%s",PMail->Data[0].Address);

3.指针访问成员

访问时可以*指针.->直接访问

printf("%s",PMail->Data[0].Name);printf("%s",PMail->Data[0].Sex);printf("%d",PMail->Data[0].Age);printf("%s",PMail->Data[0].Telephone);printf("%s",PMail->Data[0].Address);

六、结构体的计算

1.空间换取时间

效率至上:在尽可能不浪费空间的情况下,尽可能的提高运行的效率来达到我们想要的结果。所以在结构体的存储方面我们选择牺牲较少的空间,来降低计算机计算的时间复杂度,便于更快的运行程序。

2.结构体的存储

存储法则
  1. 第一个成员在与结构体变量偏移量为0的地址处。
  1. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。(对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值)。
  1. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
  1. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处。
  1. 结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
  1. 计算结构体的偏移量:offsetof (type, 成员)
  1. 修改默认最大对齐数8:#pragma pack(最大对齐数)(一般设置为2的n次方)
//计算下面代码的大小structBook{chartitle[3];intcount;shortvalue;};

题解
int的对齐数是4,而char占了3个字节,显然不是4的整数倍,于是浪费1个空白字节从而凑出4个字节恰好为int对齐数4的整数倍,此时此刻占了8个字节。short的对齐数是2个字节,8恰好是2的整数倍,所以short紧跟在int后面占2个字节,此时占用10个字节,但10并不是最大对齐数4(默认对齐数和int的对齐数取较小值)的整数倍,所以还要再浪费2个空白字节,最终结构体占用12个字节的大小。

总结

结构体提供了再相同的数据对象中存储多个不同类型数据项的方法。可以创建一个具体的结构模板,并声明相应的变量。通过.运算符和->运算符可以访问结构中的各个成员。它使得我们在处理问题时有更佳灵活的方式去解决。

http://www.jsqmd.com/news/1386202/

相关文章:

  • **发布!湖北经济学院 26 年自考专科招生简章 - 升学择校早知道
  • 5 步完成营业执照网上办理注销|2026 线上申请流程 - 信息快递
  • 规范对偶与Yang‑Mills型曲率方程:规范表示等价条件与内蕴时空的规范场刻画
  • 7个Yuzu模拟器版本终极选择指南:告别版本困扰,一键畅玩Switch游戏
  • 163MusicLyrics:跨平台音乐歌词获取与处理系统架构深度解析
  • 第22章 内存与带宽优化
  • 衢州热门短视频剪辑培训学校盘点知美人学校零基础学化妆参考 - 港焙西点-知美人美学
  • 达州市中高端牛肉牛排和牛哪里批发?在澳牧熙商用家用一站式买齐 - 品牌品鉴馆
  • 免费开源UI字体Source Sans 3怎么用:从零开始的完整上手攻略
  • 深度剖析 string —— memset memcmp
  • 江门开平DHL/UPS/FedEx/TNT国际快递:13500091568上门取件 - 烟雾弥漫L
  • 2026北京靠谱装修公司推荐,怎么避坑? - 代码装修
  • 如何使用ProGuard压缩、优化和混淆Java应用:从入门到精通
  • 从SEO到GEO,传统代运营公司为什么集体掉队?2026年真正懂AI搜索的玩家还剩几家 - 品牌推荐大师
  • 微信聊天记录导出工具终极指南:免费备份你的数字记忆
  • UniApp自定义返回与物理返回键拦截实战指南
  • 从Loop到Graph:AI时代计算范式的迁移与实战指南
  • 南京正规装修公司参考:资质、口碑、施工服务一篇看明白 - 官方资讯
  • 射雕武功排名
  • Source Sans 3 开源字体完整实战指南:从选字纠结到落地页上线
  • easy-rsa 证书签发避坑指南:新手最容易踩的 4 个坑与一次性排解法
  • 品级硅胶烘焙模具定制_耐高温防发黄易脱模_广东源头工厂代工 - 大风02
  • MulimgViewer多图像浏览器实战:一次并排看几十张图,图像对比与拼接效率立翻十倍
  • 终极Windows防撤回指南:RevokeMsgPatcher让重要消息无处遁形
  • 2026年8月普洱漏水维修攻略!梅雨季残留潮湿和汛期多雨,房屋修缮解决沉降发霉渗水难题 - 聪居到家
  • 2026年AI编程为什么从「选最强模型」转向「选对模型」?
  • 南京热门装修公司到底哪家性价比高?这份对比帮你理性选择 - 官方资讯
  • 卷积神经网络(CNN)核心原理、经典架构演进与实战指南
  • LoongCollector:高性能运维数据采集器的稳定性与性能设计实践
  • 电脑卡顿别急着换机:Mem Reduct 内存清理工具快速上手指南