自界说范例:结构体

打印 上一主题 下一主题

主题 556|帖子 556|积分 1668

一、结构体范例的声明

1、结构体的声明

  1. 结构体的声明:
  2. struct tag
  3. {
  4.         member-list
  5. };
复制代码
2、结构体变量的创建和初始化

创建一个简单的学生信息结构体
  1. struct student
  2. {
  3.         char name[20];
  4.         int age;
  5.         int score;
  6. };
复制代码
结构体默认初始化的顺序是结构体中创建变量的顺序。
初始化结构体:
  1. struct student
  2. {
  3.         char name[20];
  4.         int age;
  5.         int score;
  6. }s1, s2 = {"李华",18,88};  //第一种初始化
  7. struct student s3 = { "小明",20,100 };   //第二种初始化
  8. int main()
  9. {
  10.         struct student s4 = { "张三",15,70 };    //第三种初始化
  11.         struct student s5 = { .score = 99,.name = "小红",.age = 22 };  //第四种初始化
  12.         return 0;
  13. }
复制代码

3、特殊声明

匿名结构体
  1. struct
  2. {
  3.         int a;
  4.         char b;
  5.         float c;
  6. }x,*p;
复制代码
匿名结构体只允许利用一次,p=&a黑白法请求
4、结构体的自引用

结构体是可以进行自引用的
  1. 错误的自引用:
  2. struct stu
  3. {
  4.         int a;
  5.         struct stu next;
  6. };
  7. 正确的自引用:
  8. struct stu
  9. {
  10.         int a;
  11.         struct stu* next;
  12. };
复制代码
5、typedef重定名结构体

  1. typedef struct Node
  2. {
  3.         int data;
  4.         struct Node* next;
  5. }Node;   //结构体命名为Node
复制代码
二、结构体内存对⻬

1、对齐规则

把握结构体的对齐规则:

  • 结构体中第一个变量首对齐地址是偏移量为0的地址处。
  • 其他成员的对齐变量是范例的整数倍数的地址处。vs默认对齐量为8,linux中gcc没用对齐数,对齐数就是自身大小
  • 结构体的总大小为最大对齐数
  • 对于嵌套结构体,嵌套结构中对齐量是结构体中最大的一个变量整数倍数地址处,而竣事时是嵌套结构体的整数倍数
如盘算int 对齐数 4 8 4 int范例的大小对比默认值大小,谁小选谁是对齐数
  1. //练习1
  2. struct S1
  3. {
  4.         char c1;
  5.         int i;
  6.         char c2;
  7. };
  8. printf("%d\n", sizeof(struct S1));
  9. //练习2
  10. struct S2
  11. {
  12.         char c1;
  13.         char c2;
  14.         int i;
  15. };
  16. printf("%d\n", sizeof(struct S2));
  17. //练习3
  18. struct S3
  19. {
  20.         double d;
  21.         char c;
  22.         int i;
  23. };
  24. printf("%d\n", sizeof(struct S3));
  25. //练习4-结构体嵌套问题
  26. struct S4
  27. {
  28.         char c1;
  29.         struct S3 s3;
  30.         double d;
  31. };
  32. printf("%d\n", sizeof(struct S4));
复制代码

在以上例题中,我们发现结构体中开辟的空间有许多空间被浪费了,以是在创建范例时,需要合理的排序
在例题1与例题2中,创建的范例是一样的,就由于范例创建的顺序不一样,导致占用内存不一样。
尽量使变量小的范例排在前面

2、为什么存在内存对齐

1、平台移植问题:不是全部的硬件平台都能访问任意地址上的任意数据
2、性能问题:假如没用地址对齐,处理器需要作两次的内存访问,而对齐的内存只需要访问一次
总结来说:拿空间换时间
3、修改默认对齐数

通过利用#pragma这个预处理指令,可以改变编译器的默认对齐数
  1. #pragma pack(4)//设置对齐数变为4
  2. struct stu
  3. {
  4.         char a;
  5.         int b;
  6.         char d;
  7.         double c;
  8. };
  9. #pragma pack()//取消设置的对齐数,还原默认
  10. int main()
  11. {
  12.         printf("%zd\n", sizeof(struct stu));
  13. }
复制代码

三、结构体传参

  1. struct stu
  2. {
  3.         char name[10];
  4.         int age;
  5. };
  6. struct stu s1 = { "xiaoming",28 };
  7. void print1(struct stu s1)
  8. {
  9.         printf("%d,%s\n", s1.age, s1.name);
  10. }
  11. void print2(struct stu* s1)
  12. {
  13.         printf("%d,%s\n", s1->age, s1->name);
  14. }
  15. int main()
  16. {
  17.         print1(s1);   //传值调用
  18.         print2(&s1);  //传址调用
  19.         return 0;
  20. }
复制代码
输出:

结构体可以利用传值也可以利用传址,优先选用传址调用,如许不需要开辟新的空间,可以大大提高代码的运行效率。
四、结构体实现位段

1、什么是位段

位端可以限制结构体中创建变量占用内存的大小

  • 利用位段时,成名必须是unsigend int,int,sigent int,在c99中其他成员可以利用位段
  • 位段的创建在成员名后面加上一个冒号跟一个数字。
比如:
  1. struct stu
  2. {
  3.         int _a : 4;
  4.         int _b : 2;
  5.         int _c : 1;
  6.         int _d : 30;
  7. };
复制代码
2、位段的内存分配


  • 位段的成员可以是int,unsigent int ,signet int,char范例
  • 位段上的空间是以四个字节跟一个字节进行开辟空间的
  • 位段无法跨平台利用
  1. struct stu
  2. {
  3.         int _a : 4;
  4.         int _b : 10;
  5.         int _c : 1;
  6.         int _d : 20;
  7. };
  8. int main()
  9. {
  10.         printf("%zd\n", sizeof(struct stu));
  11.         return;
  12. }
复制代码
输出:

假如没用位段,那么4个int范例的字节大小位12
位段是如何开辟空间的,如下:

3、位段的跨平台问题

1、int位段是被当成有符号位还是无符号位是不确定的
2、位段中最大数是不确定的(有16位机器,假如设置段位超过16比特,那么就会出问题,32位机器同意也是)
3、内存是从左到右分配,还是从右到左分配是不确定的(vs是从右到左分配)
4、当一个结构体包罗两个位段时,第二个位段成员比较大,无法容纳第一个尾端剩余空间的时间,是否会舍弃剩余空间,这是不确定的。
总结:位段可以很好的节流空间,但存在跨平台问题
4、位段的应⽤

下图是⽹络协议中,IP数据报的格式,我们可以看到其中很多的属性只需要⼏个bit位就能描述,这⾥使⽤位段,可以或许实现想要的结果,也节流了空间,如许⽹络传输的数据报⼤⼩也会较⼩⼀些,对⽹络的畅通是有资助的。

5、位段使⽤的留意事项

无法获取比特位的地址。
无法直接利用scanf来输入位段,但是可以赋值位段
  1. struct stu
  2. {
  3.         int _a : 4;
  4.         int _b : 10;
  5.         int _c : 1;
  6.         int _d : 20;
  7. };
  8. int main()
  9. {
  10.         struct stu s = { 0 };
  11.         int n = 0;
  12.         scanf("%d", &n);
  13.         s._a = n;
  14.         return;
  15. }
复制代码


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

汕尾海湾

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表