最全C语言个人笔记【第五章节-联合体与枚举】

联合体(共用体)基本概念

联合体的外在形式跟结构体非常类似,但它们有一个本质的区别:结构体中的各个成员是各自独立的,而联合体中的各个成员却共用同一块内存,因此联合体也称为共用体。

在这里插入图片描述

​ 联合体各成员的堆叠效果

联合体内部成员的这种特殊的“堆叠”效果,使得联合体有如下基本特征:

  • 整个联合体变量的尺寸,取决于联合体中尺寸最大的成员。
  • 给联合体的某个成员赋值,会覆盖其他的成员,使它们失效。
  • 联合体各成员之间形成一种“互斥”的逻辑,在某个时刻只有一个成员有效。

联合体的定义:

union 联合体标签
{
    成员1;
    成员2;
    ...
};
  • 语法:
    • 联合体标签,用来区分各个不同的联合体。
    • 成员,是包含在联合体内部的数据,可以是任意的数据类型。
// 定义了一种称为 union attr 的联合体类型
union attr
{
    int x;
    char y;
    double z;  
};

int main()
{
    // 定义联合体变量
    union attr n;
}

联合体操作

联合体的操作跟结构体形式上别无二致,但由于联合体特殊的存储特性,不管怎么初始化和赋值,最终都有且仅有一个成员是有效的。

  • 初始化:
// 普通初始化:第一个成员有效(即只有100是有效的,其余成员会被覆盖)
union attr at = {100, 'k', 3.14};

// 指定成员初始化:最后一个成员有效(即只有3.14是有效的,其余成员会被覆盖)
union attr at = {
                .x  = 100,
                .y = 'k',
                .z = 3.14,
};
  • 成员引用:
at.x = 100;
at.y = 'k';
at.z = 3.14; // 只有最后一个赋值的成员有效

printf("%d\n", at.x);
printf("%c\n", at.y);
printf("%lf\n", at.z);
  • 联合体指针:
union attr *p = &at;
p->x = 100;
p->y = 'k';
p->z = 3.14;  // 只有最后一个赋值的成员有效

printf("%d\n", p->x);
printf("%c\n", p->y);
printf("%lf\n", p->z);
联合体定义与初始化
#include <stdio.h>

// 联合体声明
union node
{
    char c;
    double a;
    int b;
};

// 联合体声明并创建数据段空间
union
{
    char c;
    double a;
    int b;
}node1;

int main(int argc, char const *argv[])
{
    // 计算联合体大小
    printf("%d\n",sizeof(union node));

    // 联合体不能使用普通成员初始化
    // union node un = {12,'k',3.14};
    // printf("%d,%c,%lf\n",un.a,un.b,un.c);

    // 联合体指定成员初始化
    // 指定成员初始化的覆盖方式为从下往上覆盖,比如b会覆盖a
    // 和联合体的声明无关
    union node un = 
        {
            .c = 'k',
            .a = 3.14,
            .b = 97, 
        };
    printf("%lf,%d,%c\n",un.a,un.b,un.c);

    // 联合体成员引用
    // 指定成员初始化的覆盖方式为从下往上覆盖,比如b会覆盖a
    // 和联合体的声明无关
    union node un1;
    
    un1.a = 4.18;
    un1.b = 19;
    un1.c = 'k';
    printf("%f,%d,%c\n",un1.a,un1.b,un1.c);

    node1.a = 8.9;
    node1.b = 20;
    node1.c = 'f';
    printf("%f,%d,%c\n",node1.a,node1.b,node1.c);

    return 0;
}

联合体的使用

联合体一般很少单独使用,而经常以结构体的成员形式存在,用来表达某种互斥的属性。

  • 示例:
struct node
{
    int a;
    char b;
    double c;
    union attr at; // at内有三种互斥的属性,非此即彼
};

int main()
{
    struct node n;
    n.at.x = 100; // 使用连续的成员引用符来索引结构体中的联合体成员
}

测试大小端

#include <stdio.h>

union node
{
    int data;
    char ch;
};

int main(int argc, char const *argv[])
{
    union node n;
    n.data = 0x12345678;
    // 通过联合测试,字节序为小端模式
    printf("%x\n",n.ch);

    return 0;
}

联合体使用场景

联合体一般不会单独使用,而是以结构体的成员方式存在,用来表示互斥的效果,即一次只能赋予一个值
用来表示某种互斥属性,比如学生选修课
#include <stdio.h>

struct student
{
    char name[256];
    union 
    {
        int Chinese; // 语文
        float Math; // 数学
        double English; // 英文
    }cur;
};

int main(int argc, char const *argv[])
{
    struct student st = {
        .name = "jack",
        .cur.Chinese = 1
    };
    if(st.cur.Chinese == 1)
    {
        printf("%s选择语文课\n",st.name);
    }
    return 0;
}

枚举

枚举类型的本质是提供一种范围受限的整型,比如用0-6表示七种颜色,用0-3表示四种状态等,但枚举在C语言中并未实现其本来应有的效果,直到C++环境下枚举才拥有原本该有的属性。

  • 枚举常量列表
    • enum是关键字
    • spectrum是枚举常量列表标签,可以省略。省略的情况下无法定义枚举变量
enum spectrum{red, orange, yellow, green, blue, cyan, purple};
enum         {reset, running, sleep, stop};
  • 枚举变量
enum spectrum color = orange; // 等价于 color = 1
  • 语法要点:
    • 枚举常量实质上就是整型,首个枚举常量默认为0。
    • 枚举常量在定义时可以赋值,若不赋值,则取其前面的枚举常量的值加1。
    • C语言中,枚举等价于整型,支持整型数据的一切操作。
  • 使用举例:
switch(color)
{
    case red:
        // 处理红色...
    case orange:
        // 处理橙色...
    case yellow:
        // 处理黄色...   
}
#include <stdio.h>

// 创建枚举一般是在全局变量或者头文件
enum color{red,orange,yellow=5,green,blue,cyan,purple};

int main(int argc, char const *argv[])
{
    enum color co = blue;
    switch (co)
    {
    case red:
        printf("显示红色\n");
        break;
    case orange:
        printf("显示橙色\n");
        break;
    case blue:
        printf("显示蓝色\n");
    default:
        break;
    }
    return 0;
}
  • 枚举数据最重要的作用,是使用有意义的单词,来替代无意义的数字,提高程序的可读性。

总结:

enum weekday{mon,tue,wed,thu,fri}; // mon = 0,tue = 1,wed = 2,thu = 3,fri = 4
1.枚举第一个值默认为0
	比如mon为0,后面的大小依以此类推 1,2,3,4
	
2.如果枚举变量里面某个成员设置了数值,往后的其它成员的数值在它基础上进行累加
	enum weekday{mon,tue=100,wed,thu,fri}; // mon = 0,tue = 100,wed = 101,thu = 102,fri = 103
	
3.枚举常量实际就是一个整型,首个枚举常量默认为0

4.枚举在c语言的作用是增加代码的可读性	

练习:

设计一个小车,用枚举实现前进,后退,向左,向右四个功能,根据mode选择小车移动的方向

#include <stdio.h>

enum Car{FORWARD=1,BACK,LEFT,RIGHT};

int main(int argc, char const *argv[])
{
    
    int mode;
    printf("输入小车的运行轨迹(1:向前,2:向后,3:向左,4:向右): ");
    scanf("%d",&mode);
    enum Car MyCarMode = mode;

    switch (MyCarMode)
    {
    case FORWARD:
        printf("小车向前运动\n");
        break;

    case BACK:
        printf("小车向后运动\n");
        break;   

    case LEFT:
        printf("小车向左运动\n");
        break;   
    
    case RIGHT:
        printf("小车向右运动\n");
        break;  

    default:
        break;
    }
    return 0;
}

设计一个错误系统

#include <stdio.h>

enum errorInfo
{
    E_ERROR_DIV, // 除数不能为0
    E_ERROR_USERNAME_EXIST, // 用户名已经存在   
    E_ERROR_FILE_EXIST, // 文件存在
    E_ERROR_FILE_NOEXIST, // 文件不存在
    E_ERROR_NONE // 未知错误
};

// 定义指针数组记录错误信息
static char *error_buf[] = {
    // [0] = "除数不能为0" == *(error+0) = "除数不能为0"
    [E_ERROR_DIV] = "除数不能为0", 
    // [1] = "用户名已存在" == *(error+1) = "用户名已存在"
    [E_ERROR_USERNAME_EXIST] = "用户名已存在",
    [E_ERROR_FILE_EXIST] = "文件已存在",
    [E_ERROR_FILE_NOEXIST] = "文件不存在",
    [E_ERROR_NONE] = "未知错误"
};

char *get_errorInfo(enum errorInfo mc_erron)
{
    return error_buf[mc_erron];
}

int main(int argc, char const *argv[])
{
    int a = 0;
    int b = 0;
    //int c = a/b; // 错误
    int erron = E_ERROR_DIV;
    if(b == 0)
    {
        // 输出分母不能为0
        printf("%s\n",get_errorInfo(erron));
    }
    return 0;
}

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值