自定义范例之结构体

打印 上一主题 下一主题

主题 1802|帖子 1802|积分 5406





1.结构体范例概述

        结构体范例是一种用户自定义的数据范例,用于将不同范例的数据组合成一个整体。在C语言中,结构体利用struct关键字定义,由一系列具有相同范例或不同范例的数据构成的数据聚集,也称为结构。结构体中的数据在逻辑上是相互关联的,每个数据称为结构体的成员,成员可以有不同的数据范例,而且成员一般通过名字举行访问
2.结构体范例的特点

        每个成员具有独立的数据范例:这意味着可以在一个结构体内混淆不同范例的数据,如整数、浮点数、字符数组等。
        定义结构体时,成员数量必须固定:一旦结构体范例被定义,其成员的数量和范例就不能改变。
        成员名固定唯一且不可与结构体范例相同:每个成员必须有一个唯一的名称,且这个名称不能与结构体范例名相同。


  • 结构体范例的声明
  • 结构体范例的自引用
  • 结构体范例变量的定义、初始化和访问
  • 结构体内存对齐
  • 结构体传参
3. 结构体范例的声明

  1. #define  _CRT_SECURE_NO_WARNINGS 1
  2. #include<stdio.h>
  3. //方法一
  4. struct Stu
  5. {
  6.         char name[20];
  7.         float score;
  8.         int age;
  9. }s1,s2;//全局变量
  10. int main()
  11. {
  12.         //方法二
  13.         struct Stu s3, s4;//全局变量
  14.         return 0;
  15. }
复制代码
在C语言中,结构体(struct)是一种用户自定义的数据范例,它答应将多个不同范例的变量组合在一起。当你频繁地利用结构体时,每次都输入struct可能会显得繁琐。为相识决这个题目,C语言提供了typedef关键字,可以对结构体范例举行重命名,从而简化结构体的利用
  1. #define  _CRT_SECURE_NO_WARNINGS 1
  2. #include<stdio.h>
  3. //方法一
  4. typedef struct
  5. {
  6.         char name[20];
  7.         float score;
  8.         int age;
  9. }Stu;//全局变量
  10. int main()
  11. {
  12.         //方法二
  13.          Stu s3, s4;//全局变量
  14.         return 0;
  15. }
复制代码
注:s1,s2,s3,s4是结构体变量

4. 结构体范例的自引用(引用同范例的下一个节点)

我们先来看一下链表中的数据结构:
我们起首来定义一个整型数组:int arr[]={ 1, 2, 3, 4, 5 };


那么在结构体的自引用中我们用到的就是链表


我们通过结点在结构体中寻找下一个结点
  1. struct Node
  2. {
  3.         int data;
  4.         struct Node next;
  5. };
复制代码
如果我们这样写,就有一个大题目,就是这个结构体的大小不确定,如果结点过多,大小会一直大下去


那么我们怎么来优化呢?
解答:我们可以利用指针,因为指针在编译器中的大小是固定的4/8字节
  1. struct Node
  2. {
  3.         int data;
  4.         struct Node* next;
  5. };
复制代码

5. 结构体范例变量的定义、初始化和访问

a. 结构体指针的定义

  1. #define  _CRT_SECURE_NO_WARNINGS 1
  2. //方法一
  3. struct Point
  4. {
  5.         int a;
  6.         int b;
  7. }p1;
  8. //方法二
  9. struct Point p2;
  10. int main()
  11. {
  12.         //方法三
  13.         struct Point p3;
  14.         return 0;
  15. }
复制代码
b. 结构体指针的初始化

  1. #define  _CRT_SECURE_NO_WARNINGS 1
  2. //方法一
  3. struct Point
  4. {
  5.         int a;
  6.         int b;
  7. }p1 = {1,2};
  8. //方法二
  9. struct Point p2 = {3,4};
  10. int main()
  11. {
  12.         //方法三
  13.         struct Point p3 = {5,6};
  14.         return 0;
  15. }
复制代码
c. 结构体指针的访问

  1. #define  _CRT_SECURE_NO_WARNINGS 1
  2. #include<stdio.h>
  3. struct Point
  4. {
  5.         int x;
  6.         int y;
  7. };
  8. struct Stu
  9. {
  10.         int num;
  11.         char ch;
  12.         struct Point p;
  13.         float d;
  14. };
  15. int main()
  16. {
  17.         //顺序访问
  18.         struct Stu s1 = { 100,'a',{2,5},3.3 };
  19.         //乱序访问
  20.         struct Stu s2 = { .d = 8.9,.num = 245,.ch = 'h',.p.x = 55,.p.y = 78 };
  21.         return 0;
  22. }
复制代码

6. 结构体内存对齐

我们先来看一下这个小题
  1. #define  _CRT_SECURE_NO_WARNINGS 1
  2. #include<stdio.h>
  3. struct S1
  4. {
  5.         char c1;
  6.         int a;
  7.         char c2;
  8. };
  9. struct S2
  10. {
  11.         char c1;
  12.         char c2;
  13.         int a;
  14. };
  15. int main()
  16. {
  17.         printf("%d\n", sizeof(struct S1));
  18.         printf("%d\n", sizeof(struct S2));
  19.         return 0;
  20. }
复制代码
输出效果:


在我们的认识中,char为1个字节,int为4个字节,那么两个都应该是6才对,那为什么确实不为6且不相同的数呢?
解答:
a. 结构体内存对齐规则



  • 第一个成员的对齐:结构体的第一个成员通常从偏移量0的地址开始存储。
  • 后续成员的对齐:其他成员变量的存储地址需要是对齐数的整数倍。
对齐数是编译器默认的对齐数和该成员自身大小的较小值。


  • 结构体总大小的对齐:整个结构体的大小也会按照最大对齐数的整数倍举行对齐。这个最大对齐数是全部成员中自身对齐值最大的那个,以及指定对齐值中较小的一个。
  • 嵌套结构体的对齐:如果结构体内部有嵌套的结构体,那么嵌套的结构体也会按照上述规则举行对齐,终极结构体的整体大小将是全部最大对齐数(包罗嵌套结构体的对齐数)的整数倍。
  • 编译器默认对齐数:在不同的编译器和平台上,默认的对齐数可能不同。例如,在Linux体系中,默认对齐数可能是4字节,而在某些64位体系或Visual Studio编译器中,默认对齐数可能是8字节






  • 结构的总大小,必须是全部成员的对齐数的整数倍
在这里我们可以看见这里只占了9个内存,还不足以满足对齐数的全部条件





b. why:为什么存在内存对齐数呢?

ⅰ. 提高CPU访问数据的效率

内存对齐可以提高CPU访问数据的效率。这是因为CPU在访问内存时通常是以固定大小的块(如4字节或8字节)举行读取的。如果数据按照特定的对齐规则举行排列,CPU可以在一次访问中读取到完备的数据块,从而淘汰访问次数,提高效率。例如,如果一个int范例的数据位于4字节的边界上,那么在32位体系中,CPU可以在一个读周期内读取到这个int数据,而不需要举行额外的操作来拼接数据2。
ⅱ. 兼容性和可移植性

不同的硬件平台可能有不同的内存访问限定。有些平台只能在特定地址上访问特定范例的数据,否则可能会引发硬件异常。内存对齐可以确保步调在不同硬件平台上的一致性和可移植性。例如,Windows操作体系默认的对齐数是8,而Linux默认的对齐数是4。
ⅲ. 淘汰内存碎片

内存对齐有助于淘汰内存碎片的产生。通过将数据按照对齐规则举行排列,可以制止数据分散在内存中的各个角落,形成难以利用的小块内存,从而提高内存的利用率3。
ⅳ. 结构体和联合体的对齐规则

在C和C++编程中,结构体和联合体的成员通常需要按照一定的对齐规则举行排列。这些规则包罗数据成员的起始位置、结构体成员的对齐方式以及结构体总大小的对齐方式。通过对齐,可以确保结构体和联合体在内存中的结构符合特定的硬件平台要求,从而提高步调的实行效率和可移植性

c. 修改默认对齐数

我们用到 #pragma
  1. #define  _CRT_SECURE_NO_WARNINGS 1
  2. #include<stdio.h>
  3. #pragma pack(1)//设置默认对齐数
  4. struct S1
  5. {
  6.         char c1;
  7.         int a;
  8.         char c2;
  9. };
  10. #pragma pack()//恢复默认对齐数
  11. struct S2
  12. {
  13.         char c1;
  14.         char c2;
  15.         int a;
  16. };
  17. int main()
  18. {
  19.         printf("%d\n", sizeof(struct S1));
  20.         printf("%d\n", sizeof(struct S2));
  21.         return 0;
  22. }
复制代码
输出效果:



7. 结构体传参

a. 结构体传参分为两个方式



  • 结构体传参
  • 结构体地址传参
  1. #define  _CRT_SECURE_NO_WARNINGS 1
  2. #include<stdio.h>
  3. struct S
  4. {
  5.         int a;
  6.         int b;
  7. };
  8. struct S s= { 4,5 };
  9. //结构体传参
  10. void Print1(struct S s)
  11. {
  12.         printf("%d\n", s.a);
  13. }
  14. //结构体地址传参
  15. void Print2(struct S* pc)
  16. {
  17.         printf("%d\n", pc->b);
  18. }
  19. int main()
  20. {
  21.         Print1(s);
  22.         Print2(&s);
  23.         return 0;
  24. }
复制代码
那么结构体传参和结构体地址传参我们保举哪一个呢?
答:保举结构体地址传参
b. 为什么保举结构体地址传参

在C语言中,结构体是一种复合数据范例,它可以包含多个不同范例的成员。当需要将结构体作为参数通报给函数时,有两种重要的方式:传值和传地址。下面我们将探讨为什么通常保举利用结构体地址传参。


  • 淘汰内存开销
    当通过值通报结构体时,函数会收到结构体的一个完备副本。如果结构体非常大,这可能会导致大量的内存被不须要的复制,增加了内存开销。相比之下,通过地址通报结构体只需要通报一个指向结构体的指针,这通常只需要4字节(32位体系)或8字节(64位体系),大大淘汰了内存占用

  • 提高性能
    由于通过值通报结构领会创建结构体的副本,这不但斲丧更多的内存,还会增加CPU的负担,因为它需要额外的时间来举行数据复制。而通过地址通报则制止了这种复制,提高了步调的实行效率

  • 改变原始数据
    如果希望在函数内部对结构体的成员举行修改,而且这些修改应该反映在调用函数的上下文中,那么必须通过地址通报结构体。因为通过值通报只会通报结构体的副本,任何对副本的修改都不会影响原始结构体

  • 代码简洁性
    通过地址通报结构体可以使代码更加简洁和易读。例如,可以利用指向结构体的指针来调用结构体的方法,这在面向对象编程风格的C代码中很常见


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

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

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

本版积分规则

北冰洋以北

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表