• 【黄色手套22】6话:构造数据类型


    目录 

    序言:

    结构体:

    结构体数组:

    结构体数组的定义和引用 :

    使用关键字typedef自定义类型名:

    使用typedef语句为数组类型取别名:

    结构体所占内存的大小:

    结构体的嵌套:

    共用体类型:

            共用体类型的声明:

            共用体变量的定义:

            共用体类型所占内存:

    枚举类型:

            枚举类型的声明:

            枚举类型的使用:


    序言:

    构造数据类型:用户自己建立的数据类型(自定义数据类型)。

    C语言中的构造数据类型有:数组类型、结构体类型、共用体类型和枚举类型。

    结构体:

    用户根据自己的需求建立的由不同类型数据组成的数据类型。

    即,

    结构体这种数据类型它能根据用户需要,方便的存储各种各样的信息。

    ■.  结构体类型的声明

    (1)声明时定义结构体变量

    1. struct 结构体类型名
    2. {
    3. 成员列表;
    4. }结构体变量名; // 可以在声明时定义结构体变量名
    5. // 声明时未定义变量的话,分号(;)勿漏

    (2)先声明后定义结构体变量

              基本格式:结构体类型名 变量名;

    1. struct student s1;
    2. //s1.id=12345;

    ■.  结构体成员的使用

         基本格式:结构体变量名.成员名

         结构体成员引用符:.

         例如:

    1. #include
    2. struct pananzhongxue //构造结构体,名为“pananzhongxue”
    3. {
    4. int id;
    5. int age;
    6. float zongscore;
    7. int gender;
    8. char name[10];
    9. }s1 = {085422103,19,536,1,"chenchen"}, s2; //声明时定义结构体变量s1,s2,
    10. //并对s1初始化赋值
    11. int main()
    12. { //输出“pananzhongxue”结构体类型中的s1的各个数据
    13. printf("%d\t%d\t%d\t%f\t%s\n", s1.id, s1.age, s1.gender, s1.zongscore, s1.name);
    14. return 0;
    15. }

    说明:

    (1) struct 为结构体关键字

    (2)struct pananzhongxue 为结构体类型名

    (3)idage... 为结构体成员名

    (4)s1s2 为结构体变量

      区分清楚:结构体类型名、结构体成员名以及结构体变量

    ■.  结构体变量的定义:

      (1)可以在声明时直接定义结构体变量;

      (2)也可以先声明后定义结构体变量(用数据类型名定义结构体变量);

    1. #include
    2. struct pananzhongxue
    3. {
    4. int id;
    5. int age;
    6. float zongscore;
    7. int gender;
    8. char name[10];
    9. }s1, s2; //声明时定义结构体变量s1,s2
    10. int main()
    11. { //声明后定义结构体变量s3
    12. struct pananzhongxue s3 = {085422103,19,536,1,"xiaohei"};
    13. printf("%d\t%d\t%d\t%f\t%s\n", s3.id, s3.age, s3.gender, s3.zongscore, s3.name);
    14. return 0;
    15. }

    结构体数组

    结构体类型的数组

    ■.  结构体数组元素的使用:

    结构体数组名[数组下标].成员变量名

      例如:

    1. #include
    2. struct student
    3. {
    4. int id;
    5. int age;
    6. int height;
    7. int weight;
    8. float score;
    9. }arr1[3]; // 声明一个结构体数组arr1[3]
    10. int main()
    11. {
    12. arr1[0].id = 085422103;
    13. printf("%d\n", arr1[0].id);
    14. return 0;
    15. }

    ■.  注意数组类型的成员

      1. 数组类型int的成员,单个数据元素可以直接进行赋值:

    1. #include
    2. struct pananzhongxue
    3. {
    4. int id;
    5. int age;
    6. float score[3];
    7. int gender;
    8. char name[10];
    9. }s1, s2;
    10. int main()
    11. {
    12. s2.age[0] = 15; //数组类型单个数据元素赋值
    13. s2.age[1] = 11;
    14. s2.age[2] = 10;
    15. printf("%f\t%f\t%f\n", s2.age[0], s2.age[1], s2.age[2]);
    16. return 0;
    17. }

    2. 数组类型(如char)的成员不能直接赋值,

        可以用字符串拷贝函数strcpy来完成字符数组的赋值:

    1. #include
    2. #include //输入字符串处理函数头文件
    3. struct pananzhongxue
    4. {
    5. int id;
    6. int age;
    7. float score;
    8. int gender;
    9. char name[10];
    10. }s1,s2;
    11. int main()
    12. {
    13. strcpy(s1.name, "cc"); //用字符串拷贝函数strcpy来赋值
    14. printf("%s\n", s1.name);
    15. return 0;
    16. }

    ■.  相同结构体类型的成员可以相互赋值:

    1. #include
    2. #include
    3. struct pananzhongxue
    4. {
    5. int id;
    6. int age;
    7. float score[3];
    8. int gender;
    9. char name[10];
    10. }s1,s2;
    11. int main()
    12. {
    13. s2.score[0] = 105;
    14. s2.score[1] = 91;
    15. s2.score[2] = 110;
    16. s1.score[0] = s2.score[2]; //进行相互赋值
    17. s1.score[2] = s2.score[0];
    18. s1.score[1] = s2.score[1];
    19. printf("%f\t%f\t%f\n", s2.score[0], s2.score[1], s2.score[2]);
    20. printf("%f\t%f\t%f\n", s1.score[0], s1.score[1], s1.score[2]);
    21. return 0;
    22. }

    结构体数组的定义和引用 :

    1. #include
    2. struct student
    3. {
    4. int id;
    5. char name[10];
    6. };
    7. int main()
    8. {
    9. struct student arr1[2]={854221,"chenchen",854222,"chenhnch"};
    10. printf("id\tname\n);
    11. for(int i=0;i<2;i++)
    12. {
    13. printf("%d\t%s\n",arr1[i].id,arr1[i].name);
    14. }
    15. return 0;
    16. }

    使用关键字typedef自定义类型名:

    关键字typedef:用于给数据类型关键字取别名

    typedef的基本格式:

    typedef 数据类型名 别名;

            typedef取的别名也需要遵循标识符的命名规则。 

            typedef可以给一个数据类型取多个别名

            typedef一般使用在数据类型名比较长的情况下

    例如:

    1. #include
    2. typedef struct chenchenchenchenchen
    3. {
    4. int height;
    5. int weight;
    6. }xxx;
    7. int main(void)
    8. {
    9. xxx s1; //取别名后需再定义结构体变量名
    10. s1.height = 172;
    11. printf("%d\n", s1.height);
    12. return 0;
    13. }

    使用typedef语句为数组类型取别名:

    一维数组类型的定义格式:

    typedef 数据类型 数组名[常量];

    例如:

    1. #include
    2. typedef struct chenchenchenchenhcne
    3. {
    4. int id;
    5. char name[20];
    6. char gender[4];
    7. int age;
    8. float score[3];
    9. }CC;
    10. typedef int I[10]; // 定义了一个数组类型I
    11. // 元素类型为int
    12. // 元素个数为10
    13. int main(void)
    14. {
    15. I a = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; // 相当于int a[10]={...};
    16. // I换成a即可
    17. for (int i = 0; i < 10; i++) // 可多次定义对象(数组名)
    18. {
    19. printf("%d\t", a[i]);
    20. }
    21. putchar('\n');
    22. return 0;
    23. }

    结构体所占内存的大小:

    计算结构体内存大小时要考虑其内存布局。

    系统为了提高计算机访问数据的效率,

    在安排结构体中的每个成员时采用内存对齐的方法。

    结构体在内存中按统一单元进行存放,
    每个单元的大小取决于结构体成员中最大的基本数据类型大小。

    即,在结构体中,对不同成员类型的大小,在内存中采取内存对齐的方法以提高运行效率

    例如:

    1. #include
    2. typedef struct student
    3. {
    4. short id; //2
    5. short age; //2
    6. char name[5]; //5
    7. int height; //4
    8. int weight; //4
    9. float score; //4
    10. }xxx;
    11. int main()
    12. {
    13. printf("%d\n", sizeof(xxx)); // 24
    14. return 0;
    15. }

    内存储存如下:

    补充: 为什么要内存对齐?

    1.为了提高代码的可移植性,和提升CPU访问内存的效率(本质:以空间换时间)。

    2.不是所有的硬件平台都能访问任意地址上的数据,某些硬件平台只能在某些地址访问某些特定类型的数据,否则会抛出硬件异常,以及遇到未对齐的边界直接就不进行读取数据。 

    结构体的嵌套:

    把一个结构体的变量作为另一个结构体的成员。

    例如:

    1. #include
    2. struct student
    3. {
    4. int id;
    5. int height;
    6. int weight;
    7. char gender[3];
    8. char name[10];
    9. float score[3];
    10. }s1,s2,s3;
    11. struct teacher
    12. {
    13. int id;
    14. int height;
    15. int weight;
    16. char gender[3];
    17. char name[10];
    18. struct student s1; // 结构体嵌套
    19. }t1,t2,t3; // 结构体类型student中的变量s1是结构体类型teacher中的成员
    20. // teacher中的成员
    21. int main()
    22. {
    23. t1.s1.id = 85422103;
    24. printf("%d\n",t1.s1.id);
    25. return 0;
    26. }

    ■.  注意,一个结构体类型中可以有本身这种结构体类型的成员吗?

    1. struct teacher
    2. {
    3. int id;
    4. int height;
    5. int weight;
    6. char gender[3];
    7. char name[10];
    8. struct teacher t2; //可以吗?
    9. };

    -----会报错:不允许使用不完整的类型。

    共用体类型:

    用同一段内存单元存放不同类型的变量。

    同一个内存单元中,它们在内存中所占字节数不同,但共用同一段内存地址。

    共用体类型的声明:

    一般格式:

    1. union 共用体类型名
    2. {
    3. 成员列表;
    4. }共用体变量;

    共用体变量的定义:

    (1)声明时定义;

    (2)声明后定义;共用体类型名 变量名;

    例如:

    1. #include
    2. union student
    3. {
    4. int id;
    5. float score;
    6. char a;
    7. double b;
    8. }t1,t2;
    9. int main()
    10. {
    11. printf("%d\n", &(t1.id)); //所有输出结果相同
    12. printf("%d\n", &(t1.score)); //为共用内存的首地址
    13. printf("%d\n", &(t1.a));
    14. printf("%d\n\n", &(t1.b));
    15. printf("%d\n", &(t1.b)); //下面也是一样的
    16. printf("%d\n", &t1.b); //且每次运行会重新随机申请存储空间
    17. printf("%d\n", &t1);
    18. return 0
    19. }

    共用体类型所占内存:

    整个共用体类型所占内存是最大成员所占的内存空间(或其整数倍)

    例如:

    1. #include
    2. union student
    3. {
    4. int id; //4
    5. float score[10]; //4*10
    6. char a; //1
    7. double b; //8
    8. }t1,t2;
    9. int main()
    10. {
    11. printf("%d\n", sizeof(union student)); //8*5
    12. return0;
    13. }

    1. #include
    2. union student
    3. {
    4. int id;
    5. float score;
    6. char a;
    7. double b;
    8. }t1,t2;
    9. int main()
    10. {
    11. printf("%d\n", sizeof(union student)); //8
    12. return 0
    13. }

    注意:所占内存空间为最大基本数据类型的最小整数倍

    例如:

    1. #include
    2. union student
    3. {
    4. int id;
    5. float score;
    6. char a[10];
    7. double b;
    8. }t1,t2;
    9. int main()
    10. {
    11. printf("%d\n", sizeof(union student)); //16
    12. return0;
    13. }

    存储和读取数据时:

    1. #include
    2. union student
    3. {
    4. int id;
    5. float score;
    6. char a;
    7. double b;
    8. }t1,t2;
    9. int main()
    10. {
    11. t1.id = 0x11223344;
    12. t1.a = 0x55;
    13. printf("%x\n",t1.id); //11223355
    14. printf("%x\n",t1.a); //55
    15. return 0;
    16. }

    大端模式:

                                                                           

    共用体变量只能给一个成员初始化赋值,

    共用体同一时刻只能保存一个成员的数据(数据相应位置覆盖)

    枚举类型:

    1. 枚举类型enum:将类型中所有可能的取值一一列举出来,
    2.              枚举值只能从列举出的范围内取值,
    3.             否则没有意义。

    枚举类型可以初步简单理解为取值受限的整型,其值被按照整型数据来处理和运算。 

    如果一个变量只有几种可能的值,就可以定义为枚举类型。

    枚举类型的声明:

    1. enum 枚举类型名
    2. {
    3.    枚举元素列表;
    4. }枚举类型变量名;

    例如:

    1. enum day{
    2. sun,mon,tue,wed,thu,fri,sat
    3. }weekend,workday;
    4. //声明了一个枚举类型,数据类型名day,
    5. //其变量的取值范围为星期天至星期六,
    6. //声明时定义了两个枚举类型变量weekend和workday。

    注意:

    声明的枚举类型也可以没有类型名,

    但如果需要使用此枚举类型的话,就必须在声明时同时定义变量。

    枚举类型的使用:

       C语言中的枚举元素是按照常量进行处理的,所以又称为枚举常量。

       不能因为它们是标识符而把它们当作变量来使用,在使用时是不能对它们赋值的。

    sun=0;mon=1//错误,不能给枚举常量赋值

       每一个枚举元素都代表一个整数,

       C语言编译器按照定义时的顺序默认它们的值为0,1,2,3,4,5,6......

    workday=mon;//相当于workday=1;

       枚举常量的引用和输出:

       printf("%d",sun);   //输出整数0 

       枚举变量的引用和输出:

    1. workday=mon;
    2. printf("%d",workday);    // 输出整数1

      我们也可以人为的指定枚举元素的数值,在声明的枚举类型时指出即可。

      例如:

    1. enum weekend{sun=7,mon=1,tue,wed,thu,fri,sat}weekend,workday;
    2. // 星期二2,星期三3,......星期六6

      枚举类型可以用来进行比较和判断

    1. if(workday==mon){......};
    2. if(workday==sat){......};

      示例:

    1. #include
    2. enum weekday{sun=7,mon=1,tue,wed,thu,fri,sat};
    3. int main()
    4. {
    5. printf("%d %d %d %d %d %d %d\n", sun, mon, tue, wed, thu, fri, sat);
    6. return 0;
    7. }
    8. // 输出7 1 2 3 4 5 6

      简单的枚举类型应用示例:

      根据你输入的数字输出对应的星期数

    1. #include
    2. enum weekday{sun=7,mon=1,tue,wed,thu,fri,sat}day;
    3. int main()
    4. {
    5. while (1)
    6. {
    7. scanf("%d", &day);
    8. switch (day)
    9. {
    10. case 7:
    11. printf("你输入了周日\n");
    12. break;
    13. case 6:
    14. printf("你输入了周六\n");
    15. break;
    16. case 5:
    17. printf("你输入了周五\n");
    18. break;
    19. case 4:
    20. printf("你输入了周四\n");
    21. break;
    22. case 3:
    23. printf("你输入了周三\n");
    24. break;
    25. case 2:
    26. printf("你输入了周二\n");
    27. break;
    28. case 1:
    29. printf("你输入了周一\n");
    30. break;
    31. default:
    32. printf("你输入了无效数字\n");
    33. }
    34. }
    35. return 0;
    36. }

    _____________# 

  • 相关阅读:
    LeetCode 705. Design HashSet
    解锁Spring组件扫描的新视角
    接口自动化测试_L4
    搓一个Pythonic list
    点餐小程序实战教程06-首页开发
    react数据管理之setState与Props
    Boost Efficiency with a Unified App Testing Process
    时序分析 48 -- 时序数据转为空间数据 (七) 马尔可夫转换场 python 实践(下)
    【测控电路】三运放高共模抑制比放大电路
    图信号处理论文
  • 原文地址:https://blog.csdn.net/m0_73973059/article/details/132875246