自定义类型: 结构体 ,枚举, 共用(联合)体

短命女 2022-01-05 07:11 417阅读 0赞

自定义类型: 结构体 ,枚举, 共用(联合)体


目录

一. 结构体

  1. 结构体的声明
  2. 特殊的声明
  3. 结构体的自引用
  4. 结构体变量的定义和初始化
  5. 结构体传参
  6. 结构体内存对齐
  7. 修改默认对齐数
  8. 位段

二. 枚举

枚举的优点
枚举的定义
枚举的使用

三 .联合(共用)体

共用(联合)体的声明
共用(联合)的定义
共用(联合)的特点
共同(联合)体的大小


一. 结构体

结构体(struct)指的是一种数据结构,是C语言中聚合数据类型(aggregate data type)的一类。结构体可以被声明为变量、指针或数组等,用以实现较复杂的数据结构。结构体同时也是一些元素的集合,这些元素称为结构体的成员(member),且这些成员可以为不同的类型.

  • 结构体的声明

例如描述一个学生的信息:

  1. struct Student
  2. {
  3. char name[20];//名字
  4. int age;//年龄
  5. char sex[5];//性别
  6. char id[20];//学号
  7. };//分号不能丢

我们声明的这个自定义类型为struct Student

  • 特殊的声明

    在声明结构的时候,可以不完全的声明。例如 :

    struct{

    1. int a;
    2. char b;
    3. float c;

    }x;
    struct{

    1. int a;
    2. char b;
    3. float c;

    }a[20], *p;

    上面的两个结构在声明的时候省略了结构体标签

    我们可以看出这两个结构体内容是一样的, 那么这两个自定义类型是不是同一种类型呢 ?

    在上面代码的基础上 , 我们来看这样一段代码

    p = &x;

这段代码是不合法的 , 如图 :
20190623130050170.png

原因是编译器把上面的两个声明当成了两个不同的类型 .

  • 结构体的自引用

    如果在结构体中包含一个类型为该结构体本身的成员, 可不可以呢? 如下 :

    struct w{

    1. int a;
    2. char b;
    3. float c;
    4. struct w s;

    };

这样是不行滴, 这样会造成自递归, 一个包含一个就无穷尽了, 所以编译器会报错 .

错误的看完就该看正确的了, 正确的自引用如下:

  1. struct w{
  2. int a;
  3. char b;
  4. float c;
  5. struct w* next;
  6. };
  • 结构体变量的定义和初始化

    struct w {

    1. int a;
    2. char b;
    3. float c;

    }s1;
    struct w s2;

初始化 :

  1. struct score {
  2. int chinese;
  3. int math;
  4. int english;
  5. }s1 = { 88,89,80 };
  6. struct score s2 = { 90,45,67 };
  7. struct Student
  8. {
  9. char name[20];//名字
  10. int age;//年龄
  11. char sex[5];//性别
  12. char id[20];//学号
  13. struct score stu;
  14. }stu1 = { "张三",18,"男","12376",{ 88,89,80 } };//结构体嵌套初始化
  15. struct Student stu2 = { "李四",20,"男","12378",{ 90,45,67 } };//结构体嵌套初始化

注意:

在声明我们需要的结构体类型后, 我们定义结构体变量时, 前面的类型名很长, 让人很不舒服 . 如下代码 :

  1. struct student{
  2. int a;
  3. char b;
  4. float c;
  5. };
  6. struct student s1;
  7. struct student s2;

需要注意的是, 我们声明的自定义(结构体)类型是struct student, 并不是student .

我们可以用typedef来解决这个问题, 如下代码 :

代码1:

  1. struct student{
  2. int a;
  3. char b;
  4. float c;
  5. };
  6. typedef struct student stu;
  7. struct student s1;
  8. stu s2;

我们就可以用struct student的别名 stu 来声明s2 .

代码2:

  1. typedef struct student{
  2. int a;
  3. char b;
  4. float c;
  5. }stu;
  6. struct student s1;
  7. stu s2;

typedef也可以加在结构体声明的最前面, 此时末尾的 “ ; “ 前不再是结构体变量的声明, 而是别名 .

  • 结构体传参

我们在给函数传参数时, 有时会传值, 有时会传地址, 结构体也一样, 如下代码 :

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. typedef struct MyStruct {
  4. int arr[1000];
  5. char str[10];
  6. }S;
  7. void print_1(S x) {
  8. printf("%s\n", x.str);
  9. }
  10. void print_2(S* p) {
  11. printf("%s\n", p->str);
  12. }
  13. int main() {
  14. S a = { {1,2,3,4},"哈哈" };
  15. print_1(a);
  16. print_2(&a);
  17. system("pause");
  18. return 0;
  19. }

运行如下:
watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxMDcxMDY4_size_16_color_FFFFFF_t_70

代码中的函数 print_1 和 print_2 都可以完成打印的功能, 那么哪个更好呢 ?

答案是 print_2 , 因为函数传参的时候,参数是需要压栈(在栈中分配内存),会有时间和空间上的系统开销。
如果传递一个结构体对象的时候,结构体过大(如上面代码中的有1000个元素的数组),参数压栈的的系统开销比较大,所以会导致性能(效率)的下降, 而且在函数调用结束, 还有出栈(释放为形参分配的内存)的操作。
所以, 结构体传参的时候,传结构体的地址比较科学


  • 结构体内存对齐

  • 修改默认对齐数

  • 位段

(点击跳转)


二. 枚举

枚举在C/C++/C#中,是一个被命名的整型常数的集合

  • 枚举的优点

我们可以使用#define 定义常量,为什么非要使用枚举? 枚举的优点:

  1. 增加代码的可读性和可维护性
  2. 和#define定义的标识符相比较枚举有类型检查,更加严谨。
  3. 防止了命名污染(封装)
  4. 便于调试
  5. 使用方便,一次可以定义多个常量
  • 枚举的定义

    enum Day{

    1. 零,
    2. 星期一,
    3. 星期二,
    4. 星期三,
    5. 星期四,
    6. 星期五,
    7. 星期六,
    8. 星期七

    };

像结构体一样, 也可以没有标签

  1. enum {
  2. 零,
  3. 星期一,
  4. 星期二,
  5. 星期三,
  6. 星期四,
  7. 星期五,
  8. 星期六,
  9. 星期七
  10. };

以上两种定义方式中, 枚举中的常量都没有被赋值, 他们的值默认从0开始,依次递增1,当然在定义的时候也可以赋初值, 例如 :

  1. enum {
  2. 星期二 = 2,
  3. 星期一 = 1,
  4. 星期五 = 5,
  5. 星期六,
  6. 星期三 = 3,
  7. 星期四,
  8. 星期七 = 7
  9. };

没有初值的枚举常量都值都是上一个加一 .

  • 枚举的使用

VS2017中

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #define M 4
  4. enum day{
  5. 星期二 = 2,
  6. 星期五 = 5,
  7. 星期六,
  8. 星期三 = 3
  9. };
  10. enum day 星期七 = 星期二 + 星期五;
  11. enum day 星期四 = M;
  12. enum day 星期一 = 1;
  13. /*
  14. //不可以这样
  15. enum day 星期一;
  16. 星期一 = 1;
  17. */
  18. int main() {
  19. int Mon = 星期一;
  20. int num = 星期一 + 星期二;
  21. printf("%d %d %d %d %d %d %d\n", 星期一, 星期二, 星期三, 星期四, 星期五, 星期六, 星期七);
  22. printf("Mon = %d, num = %d\n", Mon, num);
  23. system("pause");
  24. return 0;
  25. }

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxMDcxMDY4_size_16_color_FFFFFF_t_70 1


三 .共用(联合)体

联合也是一种特殊的自定义类型 这种类型定义的变量也包含一系列的成员,特征是这些成员公用同一块空间(所以
联合也叫共用体)。

  • 共用(联合)体的声明

    union Un
    {

    1. char c;
    2. int i;

    };

  • 共用(联合)的定义

结合上面的代码 , 定义方式如下:

  1. union Un un;
  • 共用(联合)的特点

联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)。

我们来看下面这段代码 :

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. union Un
  4. {
  5. char c;
  6. int i;
  7. };
  8. int main() {
  9. union Un un;
  10. printf("%p\n", &(un.i));
  11. printf("%p\n", &(un.c));
  12. printf("%d\n", sizeof(union Un));
  13. printf("%d\n", offsetof(union Un, c));
  14. printf("%d\n", offsetof(union Un, i));
  15. system("pause");
  16. return 0;
  17. }

运行结果如下:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxMDcxMDY4_size_16_color_FFFFFF_t_70 2

我们可以看到, union Un 类型所占内存字节数是4, 和较大的成员 i (int型)保持一致, un.i 和 un.c 的地址是一样的, 并且用宏offsetof(m, s)(了解宏offsetof(m, s)请点击 )计算出, 在union Un类型中, i 和 c 成员都是从共用体所开辟的内存空间的开头开始存储的, 共用了同一段内存空间 .

  • 共同(联合)体的大小

    联合的大小至少是最大成员的大小。
    当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。

例如:

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. union Un1
  4. {
  5. char c[5];
  6. int i;
  7. };
  8. union Un2
  9. {
  10. short c[7];
  11. int i;
  12. };
  13. int main() {
  14. printf("%d\n", sizeof(union Un1));
  15. printf("%d\n", sizeof(union Un2));
  16. system("pause");
  17. return 0;
  18. }

运行如下 :

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQxMDcxMDY4_size_16_color_FFFFFF_t_70 3

union Un1 中最大成员占4字节(最大对齐数为4字节), 字符数组c占5个字节, 比最大对齐数还大, 所以对齐到最大对齐数的整数倍 ,为8。

union Un2 中最大成员占4字节(最大对齐数为4字节), 短整型数组c占14个字节, 比最大对齐数还大, 所以对齐到最大对齐数的整数倍 ,为16。


关于自定义类型就写到这, 欢迎评论补充指正(●—●)

发表评论

表情:
评论列表 (有 0 条评论,417人围观)

还没有评论,来说两句吧...

相关阅读