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

目录

[1 什么是共用体](#1 什么是共用体)

[2 共用体与结构体的区别](#2 共用体与结构体的区别)

[3 声明共用体类型](#3 声明共用体类型)

[4 声明共用体变量](#4 声明共用体变量)

[5 共用体内存分析](#5 共用体内存分析)

[6 共用体成员的获取和赋值](#6 共用体成员的获取和赋值)

[7 综合案例](#7 综合案例)

[7.1 共同体特点演示](#7.1 共同体特点演示)

[7.2 使用共用体存储学生和教师信息](#7.2 使用共用体存储学生和教师信息)


1 什么是共用体

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

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


2 共用体与结构体的区别

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

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

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


3 声明共用体类型

cpp 复制代码
union 共用体类型名称 {
    数据类型 成员名1;
    数据类型 成员名2;
    ...
    数据类型 成员名n;
};

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

cpp 复制代码
union data {
    int m;
    float x;
    char c;
};

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

4 声明共用体变量

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

cpp 复制代码
// 声明共用体类型
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:定义共用体类型的同时定义共用体变量

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

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

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

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

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

5 共用体内存分析

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

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

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

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

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

cpp 复制代码
union data a;
a.c = 4;

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

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

cpp 复制代码
union data a = {.c = 4};

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

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

cpp 复制代码
union data a = {8};

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


7 综合案例

7.1 共同体特点演示

cpp 复制代码
#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 使用共用体存储学生和教师信息

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

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

Name Num Sex Profession Score / Course
孙二娘 501 女(f) 学生(s) 89.5
吴用 1011 男(m) 老师(t) math
顾大嫂 109 女(f) 老师(t) English
林冲 982 男(m) 学生(s) 95.0
cpp 复制代码
#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);
        }
    }
}

输出结果如下所示:

相关推荐
为更好遇见17 小时前
自定义类型:结构体
c语言·windows·结构体
蟹至之3 天前
结构体 超详解
c语言·结构体·位段
2401_858286115 天前
动态内存管理练习题的反汇编代码分析(底层)
汇编·visualstudio·指针·vs·结构体·寄存器·反汇编
Thanks_ks14 天前
29 C 语言中的随机数实现:rand 与 srand
编程技巧·随机密码生成·c 语言随机数·rand 函数·srand 函数·指定范围随机数·随机数应用
2401_858286111 个月前
48.【C语言】结构体补充
c语言·开发语言·指针·结构体
职创未来官方2 个月前
大话C语言:第41篇 结构体与函数的关系
c语言·函数·结构体·嵌入式物联网·结构体与函数关系
野老杂谈2 个月前
13.3 正则表达式的应用
python·正则表达式·数据清洗·文本处理·编程技巧
SunkingYang2 个月前
在Windows编程中,MFC\C++中OnCopyData如何传递结构体类型数据?
c++·windows·mfc·结构体·wm_copydata·oncopydata
irel1a_32 个月前
#70结构体案例1(导师,学生,成绩)
c++·结构体