小编最近学完了结构体这一章节在这里梳理了这一章节的知识点分享给大家【版权与来源声明】本文为 C 语言个人学习笔记内容基于比特就业课鹏哥 C 语言课程课堂PPT与练习整理仅作非商业学习分享。课程原始课件、案例与知识点版权归属比特就业课及授课老师本人仅做个人学习笔记梳理与归纳。未经许可任何单位及个人不得转载、摘编、复制或用于商业盈利违者依法追责。本文章仅做学习参考非商业学习分享与盈利如有侵权请联系删除一、结构体1、结构体的声明结构是一些值的集合这些值称为成员变量。结构的每个成员可以是不同类型的变量1结构的声明structtag{member-list}variable-list;//声明的结构体类型structPeo{charname[20];chartele[12];charsex[5];inthigh;}p1,p2;//p1和p2是两个全局的结构体变量不建议//p1和p2是使用struct Peo结构类型创建的2个变量intmain(){structPeop3;//结构体变量的创建建议创建成局部变量return0;}2结构成员的类型结构的成员可以是标量、数组、指针甚至是其他结构体structPeo{charname[20];chartele[12];charsex[5];inthigh;};structSt{structPeop;intnum;floatf;}3结构体变量的定义和初始化structPoint{intx;inty;}p1;//声明类型的同时定义变量p1structPointp2;//定义结构体变量p2//初始化定义变量的同时赋初值structPointp3{x,y};structStu//类型声明{charname[15];//名字intage;//年龄};structStus{张王武,20};//初始化structNode{intdata;structPointp;structNode*next;}n1{10,{4,5},NULL};//结构体嵌套初始化structNoden2{20,{5,6},NULL};//结构体嵌套初始化structPeo{charname[20];chartele[12];charsex[5];inthigh;}p3,p4;structPeop5,p6;structSt{structPeop;intnum;floatf;}voidprint1(structPeop)//成员用.操作符{printf(%s %s %s %d\n,p.name,p.tele,p.sex,p.high);}voidprint2(structPeo*sp)//指针用-操作符{print(%s %s %s %d\n,sp-name,sp-tele,sp-sex,sp-high);}intmain(){structPeop1{张三,1234567890,男,181};//结构体变量的创建structSts{{李四,0987654321,女,167},100,3.14f};//注意浮点数在内存中不能精确保存printf(%s %s %s %d\n,p1.name,p1.tele,p1.sex,p1.high);printf(%s %s %s %d %d %f\n,s.p.name,s.p.tele,s.p.sex,s.p.high,s.num,s.f);print1(p1);//传入成员print2(p1);//传地址结构体return0;}结构变量的成员是通过操作符.访问的.操作符**接受两个操作数 **结构体指针访问指向变量的成员有时候我们得到的不是一个结构体变量而是指向一个结构体的指针4结构的特殊声明在声明结构体的时候可以不完全的声明struct{inta;charb;floatc;}x;struct{inta;charb;floatc;}a[20],*p;//p x;//非法编译器会把上面的两个声明当成完全不同的两个类型所以是非法的匿名的结构体类型如果没有对结构体类型重命名的话基本上只能使用一次2、结构的自引用structNode{intdata;structNode*next;};typedefstructNode{intdata;structNode*next;}Node;3、结构体内存对齐是拿牺牲空间换取时间效率的做法1对齐规则① 结构体的第一个成员对齐到和结构体变量起始位置偏移量为 0 的地址处② 从第二个成员变量开始都要对齐到某个对齐数\textcolor{red}{对齐数}对齐数的整数倍的地址处对齐数 编译器默认的一个对齐数与该成员变量大小的较小值VS中默认值为 8Linux中gcc没有默认对齐数对齐数就是成员自身的大小③结构体总大小为最大对齐数结构体中每个变量都有一个对齐数所有对齐数中最大的的整数倍④ 如果嵌套了结构体的情况嵌套的结构体成员对齐到自己成员中最大对齐数的整数倍处结构体的整体大小就是所有最大对齐数含嵌套结构体中成员的对齐数的整数倍#includestdio.hstructS1{charc1;inti;charc2;};structS2{charc1;charc2;inti;};structS3{doubled;charc;inti;};structS4{charc1;structS3s3;doubled;};第一步看 S3 的 “身份” S3 里面有double8字节所以 S3 的对齐要求8意思是S3 必须放在8的倍数地址上0、8、16、24... 第二步开始排 S4 的内存charc1 占1字节 地址0用到地址0structS3s3 要求必须放在8的倍数地址 现在只用到了地址0下一个8的倍数是8所以地址1~7必须空着填充7字节 S3 从地址8开始放占16字节 → 用到地址8~23doubled 要求放在8的倍数地址 上一个用完到23下一个8的倍数是24直接放占8字节 → 用到地址24~31第三步算总大小 从0~31一共32字节刚好是8的倍数完美对齐intmain(){printf(%zu\n,sizeof(structS1));//12printf(%zu\n,sizeof(structS2));//8printf(%zu\n,sizeof(structS3));//16printf(%zu\n,sizeof(structS4));//32return0;}以struct S1为例分析那么在设计结构体的时候我们既要满足对齐又要节省空间让占用空间小的成员尽量集中在一起structS1{charc1;charc2;inti;};2修改默认对齐数使用pragma这个预处理指令#includestdio.h#pragmapack(1)//设置默认对齐数为1structS{charc1;inti;charc2;};#pragmapack()//取消设置的对齐数还原为默认intmain(){printf(%zu\n,sizeof(structS));//6return0;}结构体在对齐方式不合适的时候我们可以自己更改默认对齐数4、结构体传参structPeo{charname[20];chartele[12];charsex[5];inthigh;}p3,p4;structPeop5,p6;structSt{structPeop;intnum;floatf;}voidprint1(structPeop)//成员用.操作符{printf(%s %s %s %d\n,p.name,p.tele,p.sex,p.high);}voidprint2(structPeo*sp)//指针用-操作符{print(%s %s %s %d\n,sp-name,sp-tele,sp-sex,sp-high);}intmain(){structPeop1{张三,1234567890,男,181};//结构体变量的创建structSts{{李四,0987654321,女,167},100,3.14f};//注意浮点数在内存中不能精确保存print1(p1);//传入成员print2(p1);//传地址结构体return0;}结构体传参的时候要传结构体的地址函数传参的时候参数是需要压栈的会有时间和空间上的系统开销如果传递一个结构体对象的时候结构体过大参数压栈的系统开销比较大会导致性能的下降5、结构体实现位段1什么是位段① 位段的成员必须是int、unsigned int或signed int在C99中位段成员的类型也可以选择其他整型家族类型如char② 位段的成员名后边有一个冒号和一个数字#includestdio.hstructA{int_a:2;int_b:5;int_c:10;int_d:30;};intmain(){printf(%zu\n,sizeof(structA));//8//开始算 struct Aint一共32位我们一个个塞 _a:2→ 用掉2位 → 剩30位 _b:5→ 用掉5位 → 剩25位 _c:10→ 用掉10位 → 剩15位 _d:30→ 需要30位 现在只剩15位不够 → 放弃这15位新开一个int32位 → 把 _d 放进去//最终占用空间第1个int4字节 第2个int4字节 总大小8字节return0;}上面的A就是一个位段类型2位段的内存分配位段的成员可以是int、unsigned int、signed intchar位段的空间上是按照需要以 4 个字节int或者 1 个字节char的方式来开辟的位段涉及很多不确定性因素位段是不跨平台的注重可移植性的程序应该避免使用位段int位段被当成有符号数还是无符号数是不确定的位段中最大位的数目不能确定16 位机器最大 1632 位机器最大 32写成 27在16位机器上会出问题位段中的成员在内存中从左向右分配还是从右向左分配标准上未定义当一个结构体包含两个位段第二个位段成员比较大无法容纳第一个位段剩余的位时是舍弃剩余的位还是利用这也是不确定的总的来说跟结构体相比位段可以达到同样的效果并且可以很好的节省空间但是有跨平台性的问题存在位段的应用网络传输IP数据报3位段的使用注意事项位段的几个成员共有同一个字节这样有些成员的起始位置并不是某个字节的起始位置那么这些位置处是没有地址的内存中每个字节分配一个地址一个字节内部的bit位是没有地址的所以不能对位段的成员使用操作符这样就不能使用scanf()直接给位段的成员输入值只能是先输入放在一个变量中然后赋值给位段的成员#includestdio.hstructA{int_a:2;int_b:5;int_c:10;int_d:30;};intmain(){structAsa{0};scanf(%d,sa._b);//errorintb0;scanf(%d,b);sa._bb;//truereturn0;}#includestring.hintmain(){unsignedcharpuc[4];structtagPIM{unsignedcharucPim1;//占一字节unsignedcharucData0:1;//1bitunsignedcharucData1:2;//2bitunsignedcharucData2:3;//3bit}*pstPimData;pstPimData(structtagPIM*)puc;memset(puc,0,4);pstPimData-ucPim12;//整个字节置为2pstPimData-ucData03;//0000 0011 根据位段按位取舍从右到左修改pstPimData-ucData14;//0000 0100 根据位段按位取舍从右到左修改pstPimData-ucData25;//0000 0101 根据位段按位取舍从右到左修改printf(%02x %02x %02x %02x\n,puc[0],puc[1],puc[2],puc[3]);//0000 0010 0010 1001 0000 0000 0000 0000// 02 29 00 00//02x表示按两位十六进制打印不足的补0return0;}struct_Record_Struct{// 第 1 字节unsignedcharEnv_Alarm_ID:4;// 4位unsignedcharPara1:2;// 2位// 426位 → 还剩2位放不下后面的独立char所以结束// 第 2 字节独立字节不是位段unsignedcharstate;// 8位// 第 3 字节unsignedcharavail:1;// 1位};struct_Record_Struct*pointer(struct_Record_Struct*)malloc(sizeof(struct_Record_Struct)*23);//3*239结构体大小3字节sizeof(...)*233×239代码作用动态申请9字节内存【版权与来源声明】本文为 C 语言个人学习笔记内容基于比特就业课鹏哥 C 语言课程课堂PPT与练习整理仅作非商业学习分享。课程原始课件、案例与知识点版权归属比特就业课及授课老师本人仅做个人学习笔记梳理与归纳。未经许可任何单位及个人不得转载、摘编、复制或用于商业盈利违者依法追责。本文章仅做学习参考非商业学习分享与盈利如有侵权请联系删除好啦小编今天的分享就到这里如果有勘误的地方还请大家帮忙指出哦