尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
C语言学习笔记(八):结构体进阶
目录1. 结构体类型声明进阶1.1 嵌套结构体类型1.2 结构体的自引用1.3 typedef简化结构体类型1.4 匿名结构体类型2. 结构体数组3. 结构体内存对齐3.1 对齐规则3.2 为什么存在内存对齐3.3 结构体设计的技巧3.4 修改默认对齐数1. 结构体类型声明进阶1.1 嵌套结构体类型在之前章节中我们学习了结构体的基本声明。今天我们来探讨嵌套结构体类型——也就是在结构体类型中包含其他结构体类型。场景描述一个学生学生信息包含名字、生日年、月、日、性别、学号。我们可以把生日也设计成一个独立的struct Date结构体类型然后在struct Student中嵌套它。#includestdio.h// 描述日期structDate{intyear;intmonth;intday;};// 描述学生信息嵌套了Date结构体structStudent{charname[20];structDatebirthday;// 嵌套结构体charid[20];};intmain(){// 嵌套结构体的初始化用 { } 套 { }structStudents{aoyun,{2008,8,8},2026010102};// 成员的访问通过 . 一层一层访问printf(生日:%d-%d-%d\n,s.birthday.year,s.birthday.month,s.birthday.day);return0;}访问方式结构体变量.嵌套结构体变量.成员名如s.birthday.year1.2 结构体的自引用结构体的自引用是指在结构体内部包含一个指向同类型结构体的指针。这是实现链表等数据结构的基础。错误写法❌ 会导致无穷递归无法计算大小structNode{intdata;structNodenext;// ❌ 错误包含了同类型的完整结构体会无限递归};正确写法✅ 用指针structNode{intdata;structNode*next;// ✅ 正确指针大小固定4或8字节};为什么这样可行每个节点需要存储数据还要能找到下一个节点。只需存储下一个节点的地址指针就能通过指针找到下一个节点。指针的大小是固定的32位下4字节64位下8字节不会造成无限递归。示意图节点1 节点2 节点3 ------ ------ ------ | data | | data | | data | | next |----| next |----| next |---- NULL ------ ------ ------1.3 typedef简化结构体类型struct Student写起来有点长可以用typedef给它起一个简短的别名。没有typedef时structStudent{charname[20];intage;};structStudents1;// 每次都要写 structstructStudents2;使用typedef后typedefstructStudent{charname[20];intage;}Student;// Student 就是 struct Student 的别名Student s1;// 简洁多了Student s2;包含自引用的结构体也可以使用typedeftypedefstructNode{intdata;structNode*next;// 注意这里必须写 struct Node不能写 Node}Node;Node n1{0};注意在结构体内部自引用时typedef的别名还未生效所以必须写完整的struct Node。1.4 匿名结构体类型匿名结构体类型是指在声明时省略了结构体标签tag。// 匿名结构体类型同时创建了变量xstruct{inta;charb;floatc;}x;特点匿名结构体类型只能使用一次就是定义变量这一次之后不能再用来创建新变量。即使两个匿名结构体的成员完全相同编译器也会把它们当成完全不同的类型。struct{inta;charb;floatc;}x;struct{inta;charb;floatc;}a[20],*px;// ❌ 错误x 不能赋值给 p因为类型不同使用typedef给匿名结构体起别名typedefstruct{inta;charb;floatc;}X;// X就是新类型名X x1;// 创建全局变量intmain(){X x2;// 创建局部变量return0;}2. 结构体数组就像有整型数组、字符数组一样我们也可以有结构体数组用来存放多个结构体变量。#includestdio.hstructDate{intyear;intmonth;intday;};typedefstructStudent{charname[20];structDatebirthday;charid[20];}Student;intmain(){// 结构体数组的初始化Student stu_arr[3]{{zhangsan,{2008,8,8},2026010101},{lisi,{2009,1,10},2026010102},{wangwu,{2009,3,20},2026010103}};// 遍历结构体数组for(inti0;i3;i){printf(name:%s\tbirth:%d-%d-%d\tid:%s\n,stu_arr[i].name,stu_arr[i].birthday.year,stu_arr[i].birthday.month,stu_arr[i].birthday.day,stu_arr[i].id);}return0;}3. 结构体内存对齐这是一个非常重要的考点先看一段代码猜猜输出结果是多少#includestdio.hstructS1{charc1;charc2;inti;};structS2{charc1;inti;charc2;};intmain(){printf(%zu\n,sizeof(structS1));printf(%zu\n,sizeof(structS2));return0;}输出结果8 12两个结构体的成员完全一样只是顺序不同但大小却不同这就是结构体内存对齐导致的。3.1 对齐规则第一个成员对齐到结构体起始位置偏移量为0。从第二个成员开始每个成员都要对齐到对齐数的整数倍偏移处。对齐数 编译器默认对齐数 与 成员自身大小的较小值VS中默认对齐数为8Linuxgcc没有默认对齐数对齐数就是成员自身大小结构体总大小必须是所有成员中最大对齐数的整数倍。嵌套结构体嵌套的结构体对齐到自己的最大对齐数的整数倍偏移处整体大小为所有最大对齐数的整数倍。以 struct S2 为例分析VS默认对齐数8成员自身大小对齐数起始偏移占用的字节c1 (char)1100i (int)4444~7c2 (char)1188总大小9对齐到最大对齐数4的整数倍 →12S2的内存布局 | c1 | 填充 | 填充 | 填充 | i4字节 | c2 | 填充 | 填充 | 填充 | 0 1 2 3 4 5 6 7 8 9 10 11 ↑ ↑ ↑ 偏移0 偏移4 偏移83.2 为什么存在内存对齐原因1平台原因移植性某些硬件平台只能在特定地址取特定类型的数据否则会抛出硬件异常。原因2性能原因现代CPU不是逐字节读写内存的而是按块通常4或8字节读取。如果数据是对齐的CPU只需一次内存访问如果数据不对齐CPU需要两次访问并拼接性能明显下降。总结结构体内存对齐是用空间换取时间的做法通过填充少量字节换取更快的CPU访问速度。3.3 结构体设计的技巧既然对齐会带来空间浪费我们可以通过合理安排成员顺序来节省空间。技巧将占用空间小的成员尽量集中在一起。// ❌ 浪费空间大的放在中间structS1{charc1;inti;charc2;};// 大小12字节// ✅ 节省空间小的集中在一起structS2{charc1;charc2;inti;};// 大小8字节两个结构体的成员一模一样只是顺序不同struct S2就比struct S1少了4个字节3.4 修改默认对齐数在VS中可以使用#pragma pack()来修改默认对齐数。#includestdio.h#pragmapack(1)// 设置默认对齐数为1structS{charc1;inti;charc2;};#pragmapack()// 取消设置恢复默认intmain(){printf(%zu\n,sizeof(structS));// 输出6无对齐填充return0;}对齐数为1时相当于没有对齐结构体大小为所有成员大小之和。总结嵌套结构体结构体里面可以套结构体用.一层层访问。自引用结构体内部用指针指向同类型结构体是链表的基础。typedef给结构体起别名让代码更简洁。匿名结构体没有名字的结构体只能使用一次不推荐使用。内存对齐结构体成员在内存中不是紧密排列的会为了CPU访问效率而填充字节。对齐规则每个成员对齐到对齐数的整数倍总大小为最大对齐数的整数倍。节省空间的技巧将占用空间小的成员集中在一起。修改对齐数使用#pragma pack()可以修改默认对齐数。
RELATED

相关推荐

测试压缩技术与EDT架构

测试压缩技术与EDT架构

测试压缩技术与EDT架构 芯片DFT系列博客之七:从测试数据量爆炸到EDT架构详解,深入剖析测试压缩原理、编码技术与工程实践 引言 随着SoC设计规模迈入十亿门级时代,测试数据量呈现爆炸式增长。一颗现代芯片的扫描测试数据可能高达数十Gbit,若不采用压缩技术,ATE(自动测试设…

📅 2026/10/7 17:57:51
从大众自动驾驶宣言看L4技术落地:硬件堆料、算法挑战与行业转向

从大众自动驾驶宣言看L4技术落地:硬件堆料、算法挑战与行业转向

1. 从“画饼”到“上路”:2021年大众自动驾驶宣言的行业背景 2021年,当大众汽车集团高调宣布其“计划在2021年实现全自动驾驶车型上路”时,整个汽车圈和科技圈都为之侧目。这不仅仅是一家传统汽车巨头的技术路线图更新,更像是一枚…

📅 2026/10/10 2:35:05
英国APC 4100万美元动力总成基金:技术路线、申请策略与产业启示

英国APC 4100万美元动力总成基金:技术路线、申请策略与产业启示

1. 项目背景:一场重塑汽车产业链的“军备竞赛” 最近,汽车行业的朋友圈和行业媒体都被一条消息刷屏了:一家名为APC(Advanced Propulsion Centre UK,英国先进推进中心)的机构,发起了一项总额高达…

📅 2026/10/20 0:44:24
MORE NEWS

更多资讯

📰

可直接套用的产品需求文档模板:编号追溯、验收口径与变更管理

简介:这份经典产品需求文档(PRD)模板面向产品经理、需求分析师以及刚入行的互联网从业者,主要解决需求文档结构零散、版本变更难以追溯的问题。模板从文档基本信息、接收人签字和修改记录入手,依次覆盖概要介绍、项目概…

📰

Kettle数据同步:并发行集与元数据避坑指南

简介:围绕ETL与Kettle基础制作的PPT讲解材料,面向具备一定编程和数据库基础、工作1—3年的研发人员,用于快速建立数据抽取、转换、装载的整体认知,并熟悉Kettle(PDI 9.2)的安装与使用。压缩包共1个pptx文件…

📰

SRS需求规约模板拆解:六章骨架、落地流程与追踪矩阵

简介:这份文档围绕IBM软件需求规约(SRS)的格式要求与案例展开,面向项目经理、需求分析人员、开发及测试QA团队,帮助读者在项目早期组织完整需求、明确系统外部行为,并为需求讨论、设计输入和测试用例编写提…

📰

IPD评审要素表:TR与DCP双线评审从概念到量产

简介:面向产品研发管理者、项目经理与IPD流程推行人员的评审要素参考文档,按Phase0各阶段与TR1至TR6评审点逐条梳理查核要点,解决评审无据可依、交付物责任不清的问题。文档以表格形式明确每个评审要素对应的文档或交付物、资料提供部门及资料…

📰

Kettle/PDI零基础入门:从数据同步到首个ETL转换实战

简介:《ETL之kettle基础-PPT讲解》是一份面向具备一定编程基础、工作1—3年研发人员的入门型课件,聚焦ETL与Kettle(PDI)的基础认知及项目落地前的知识准备,帮助读者理解数据抽取、转换、装载的流程,并熟悉以…

📰

辩证法仅是表象浅层规则| 赵杰 | 量子哲学

作者:赵杰清华大学硕士、微美全息云科技(NASDAQ:WIMI)董事长、微算法科技(NASDAQ:MLGO)董事长、育杰奖学金创始人总前置理论铺垫(理解辩证矛盾的两大底层根基)一、爱子论…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬