超详细最全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[])
{
    // int data = 0x12345678;
    // char *p = (char *)&data;
    // printf("%x\n",*(p+1)); // 小端

    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 {MOVE,BACK,LEFT,RIGHT};

int main(int argc, char const *argv[])
{
    int mode = BACK;
    switch (mode)
    {
    case MOVE:
        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 Error_Code
{
    MUSIC_ERR_SUCCESS = 0, // 成功
    MUSIC_ERR_PARAM = 1, // 参数错误
    MUSIC_ERR_NOT_INIT = 2, // 未初始化
    MUSIC_ERR_APPLY_MEMORY = 3, // 申请内存失败
    MUSIC_ERR_NET_EXCEPTION = 4, // 网络异常
    MUSIC_ERR_OTHER = 10000 // 其它
};

// 管理错误码
char *errorCode[] = {
        [MUSIC_ERR_SUCCESS]       = "成功",
        [MUSIC_ERR_PARAM]         = "参数错误",
        [MUSIC_ERR_NOT_INIT]      = "未初始化",
        [MUSIC_ERR_APPLY_MEMORY]  = "申请内存失败",
        [MUSIC_ERR_NET_EXCEPTION] = "网络异常",
        [MUSIC_ERR_OTHER]         = "其它错误"
}; 

//char buf[] = "成功"
//char *buf[10] = {[0] = "成功",[1] = "参数错误"};
char *buf[10] = {[MUSIC_ERR_SUCCESS] = "成功",[MUSIC_ERR_PARAM] = "参数错误"};

char *getErrorCode(int g_error)
{
    return errorCode[g_error];
}

int main(int argc, char const *argv[])
{
    printf("%s\n",getErrorCode(MUSIC_ERR_NOT_INIT));
    return 0;
}

同志们 我一直在!

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值