41 C 语言共用体:共用体数据类型、共用体变量、访问共用体成员、与结构体的区别

目录

1 什么是共用体

2 共用体与结构体的区别

3 声明共用体类型

4 声明共用体变量

5 共用体内存分析

6 共用体成员的获取和赋值

7 综合案例

7.1 共同体特点演示

7.2 使用共用体存储学生和教师信息


1 什么是共用体

        共用体(Union)是一种特殊的数据结构,允许不同数据类型的成员共享同一块内存区域。这意味着,在任意时刻,共用体中只有一个成员是有效的,因为新赋值的成员会覆盖前一个成员的值。

        共用体主要用于需要节省内存或处理多种数据类型但每次只使用其中一种的情况。例如,表示学生的成绩时,成绩可能以不同的形式给出——整数(80、90)、字符等级('A'、'B')或是浮点数分数(80.5、60.5)。


2 共用体与结构体的区别

特性/类型结构体 (Struct)共用体 (Union)
内存分配每个成员分配独立的内存空间所有成员共享同一块内存空间
内存大小总内存大小可以认为是所有成员内存大小之和总内存大小等于最大成员的内存大小
数据访问可以同时访问所有成员同一时间只能有效访问一个成员
成员存储每个成员有自己的内存地址所有成员的起始地址相同
初始化可以初始化多个成员只能初始化第一个成员
适用场景需要存储和同时访问多个不同数据类型的数据需要节省内存且每次只使用其中一个成员的情况
类型安全更类型安全,每个成员有明确的类型类型安全性较低,容易发生类型混淆

        结构体:每个成员都有独立的内存空间,结构体所占用的总内存可以认为是所有成员占用内存之和(实际内存占用会受到对齐(alignment)的影响)。可以同时访问所有的成员,每个成员都有自己独特的内存地址

        共用体:所有成员共享同一块内存,共用体所占用的内存大小取决于其最大的成员。一次只能有效访问一个成员,访问不同的成员时,实际上是在查看同一内存区域的不同解释


3 声明共用体类型

union 共用体类型名称 {
    数据类型 成员名1;
    数据类型 成员名2;
    ...
    数据类型 成员名n;
};

        下面的 union data 定义了一个名为 data 的共用体类型,该类型包含三个成员:一个整数 m、一个浮点数 x 和一个字符 c。

union data {
    int m;
    float x;
    char c;
};

        该共用体所有成员共享同一块内存,共用体的总内存大小等于其最大成员的大小。在大多数系统中,float 类型通常占用 4 个字节,因此 union data 也将占用 4 个字节。需要注意的是:同一时间只能有效访问一个成员,最后一个被赋值的成员是当前有效的成员

4 声明共用体变量

方式 1:先定义共用体类型,再定义共用体变量

// 声明共用体类型
union data {
    short m;
    float x;
    char c;
};

// 声明共用体变量
union data a, b;

        首先定义一个共用体类型 union data,其中包含三个成员:short m、float x 和 char c。 然后在单独的语句中声明共用体变量 a 和 b,这两个变量都是 union data 类型。

方式 2:定义共用体类型的同时定义共用体变量

// 定义共用体类型并声明共用体变量
union data {
    short m;
    float x;
    char c;
} a, b;

        在同一行中定义共用体类型 union data 并同时声明共用体变量 a 和 b。这种方式简洁,减少了代码量。 

方式3:在定义时也可以不给出共用体名

// 定义共用体类型并声明共用体变量,不给出共用体名
union {
    short m;
    float x;
    char c;
} a, b;

        定义共用体时不给出共用体名,直接在定义时声明共用体变量 a 和 b。这种方式适用于不需要多次使用该共用体类型的情况。

5 共用体内存分析

// 定义共用体类型并声明共用体变量
union data {
    short m;
    float x;
    char c;
} a;

        上面这个共用体它由3个成员组成,分别是 m、x 和 c,系统会按照最长的成员为它分配内存,由于成员 x 的长度最长,它占 4 个字节,所以共用体变量 a 的内存空间也为 4 个字节。

6 共用体成员的获取和赋值

        同结构体一样,共用体也使用点号. 获取单个成员,可以进行赋值和取值。

方式 1:先声明共用体变量,再赋值

union data a;
a.c = 4;

        首先声明一个共用体变量 a。然后使用点号 . 给成员 c 赋值为 4。 

方式 2:声明共用体变量的同时,给任一成员赋值

union data a = {.c = 4};

        在声明共用体变量 a 的同时,使用指定成员的方式给成员 c 赋值为 4。这种方式明确指定了赋值的成员,提高了代码的可读性。 

方式 3:声明共用体变量的同时,给首成员赋值

union data a = {8};

        在声明共用体变量 a 的同时,给第一个成员赋值为 8。这种方式不指定成员名,因此只能为第一个成员赋值。如果共用体的第一个成员是 short m,则 m 将被赋值为 8。


7 综合案例

7.1 共同体特点演示

#include <stdio.h>

// 方式1
union data
{
    short m;
    float x;
    char c;
};
union data a1, b1;

// 方式2
union data2
{
    short m;
    float x;
    char c;
} a2, b2;

// 方式3
union
{
    short m;
    float x;
    char c;
} a3, b3;

int main()
{

    // 赋值并访问
    // 方式1
    a1.m = 100;
    b1.x = 3.14;
    // 打印方式1
    printf("a1.m: %hd\n", a1.m);  // 100
    printf("b1.x: %.2f\n", b1.x); // 3.14

    // 方式2
    a2.c = 'A';
    b2.m = 200;
    // 打印方式2
    printf("a2.c: %c\n", a2.c);  // A
    printf("b2.m: %hd\n", b2.m); // 200

    // 方式3
    a3.x = 2.71;
    b3.c = 'B';
    // 打印方式3
    printf("a3.x: %.2f\n", a3.x); // 2.71
    printf("b3.c: %c\n", b3.c);   // B

    // 注意:访问其他成员时,值可能已经被覆盖
    // 在任意时刻,共用体中只有一个成员是有效的
    // 访问不同的成员时,实际上是在查看同一内存区域的不同解释
    a1.c = 'a';
    printf("a1.c: %c\n", a1.c);  // a
    printf("a1.m: %hd\n", a1.m); // 97,这是 a 转换成的数值 97
    printf("a1.x: %f\n", a1.x);  // 0.000000,字符转换成浮点数

    // 共用体所占用的内存大小取决于其最大的成员
    printf("共用体a1的长度为:%zu\n", sizeof(a1));   // 4,成员最大的是 float 类型,所以为 4
    printf("float类型的长度:%zu\n", sizeof(float)); // 4
    printf("short类型的长度:%zu\n", sizeof(short)); // 2
    printf("char类型的长度:%zu\n", sizeof(char));   // 1

    return 0;
}

        输出结果如下所示:

7.2 使用共用体存储学生和教师信息

        现有一张关于学生信息和教师信息的表格。学生信息包括姓名、编号、性别、职业、 分数,教师的信息包括姓名、编号、性别、职业、教学科目:可以参考下面的表格。

        请利用共用体,只使用一个结构体保存每个人的信息。

NameNumSexProfessionScore / Course
孙二娘501女(f)学生(s)89.5
吴用1011男(m)老师(t)math
顾大嫂109女(f)老师(t)English
林冲982男(m)学生(s)95.0
#include <stdio.h>
#define TOTAL 2 // 定义人员总数

// 定义了一个结构体 Person
struct Person
{
    char name[20];   // 姓名
    int num;         // 编号
    char sex;        // 性别 (f: 女, m: 男)
    char profession; // 职业 (s: 学生, t: 老师)
    union
    {                    // 共用体,用于存储学生的分数或教师的教学科目
        float score;     // 学生的分数
        char course[20]; // 教师的教学科目
    } sc;                // sc 是一个共用体变量
};

// 以表格形式打印输出所有人的信息
void printTableInfo(struct Person *p);

int main()
{
    struct Person persons[TOTAL]; // 定义了一个结构体数组,用于存储多个人的信息

    // 输入人员信息
    for (int i = 0; i < TOTAL; i++)
    {
        printf("请输入第%d人的信息,格式:姓名 编号 性别 (f: 女, m: 男) 职业 (s: 学生, t: 老师)\n", i + 1);
        scanf("%s %d %c %c", persons[i].name, &(persons[i].num), &(persons[i].sex), &(persons[i].profession));

        if (persons[i].profession == 's')
        { // 如果是学生
            printf("请输入该学生成绩:");
            scanf("%f", &persons[i].sc.score);
        }
        else
        { // 如果是老师
            printf("请输入该老师课程:");
            scanf("%s", persons[i].sc.course);
        }
        fflush(stdin); // 刷新输入缓冲区
    }

    // 调用输出函数
    printTableInfo(persons);

    return 0;
}

void printTableInfo(struct Person *p)
{
    // 输出人员信息
    printf("\n姓名\t\t编号\t性别\t职业\t成绩 / 科目\n");

    for (int i = 0; i < TOTAL; i++)
    {
        if (p[i].profession == 's')
        { // 如果是学生
            printf("%s\t\t%d\t%c\t%c\t\t%.1f\n",
                   p[i].name, p[i].num, p[i].sex, p[i].profession, p[i].sc.score);
        }
        else if (p[i].profession == 't')
        { // 如果是老师
            printf("%s\t\t%d\t%c\t%c\t\t%s\n",
                   p[i].name, p[i].num, p[i].sex, p[i].profession, p[i].sc.course);
        }
    }
}

        输出结果如下所示:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Thanks_ks

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值