C的实用笔记43——共用体/联合体

1.啥是共用体?和结构体有什么区别?

1、共用体的概念:不同类型的变量共享一块内存空间

2、共用体与结构体的区别:

  1. 相同点:共用体和结构体一样,都是构造类型,长的差不多。
  2. 不同点:
    1. 结构体变量中的成员变量有各自单独空间。共用体变量中的成员变量共享空间,空间大小由最大类型确定。
    2. 结构体变量中的成员变量互不影响,但是对共用体变量中的成员变量赋值会导致覆盖。

2.共用体变量的四要素

与普通变量的四要素完全相同。

1、共用体变量的类型:也就是共用体,它是我们自创的类型,也是构造类型。它的声明通常不放在函数中,书写的方式就像全局变量,因为它要尽可能让程序中的所有位置都能使用这个类型声明。共用体又有三部分:

  1. union关键字:表示构造的是共用体。
  2. 共用体类型名:和结构体一样,编程习惯是用大写开头,小写开头虽然不出错,就是看起来太low了。
  3. 共用体成员列表:和结构体一样,成员列表也称为域表,通常我们称结构体成员列表(域表)中的每个成员为成员变量(域),成员变量之间用分号隔开。你可以定义许多成员变量,但并不是每一个选项在具体使用中会被派上用场,不要给成员变量赋值,虽然不出错,但是看起来太low了。
    union Test				//union是关键字,Test是自己取的共用体类型名
    {						//花括号中的是共用体成员列表
        char cdata;
        int idata;
        double ddata;
    };						//从此以后,我们构造了一个共用体,它是 union Test 类型。

1、共用体的知识点:

  1. 共用体声明时,末尾加分号;
  2. 共用体这个构造类型,决定了共用体变量占用空间的大小,系统会在程序运行或编译阶段给你静态分配好内存。可以肯定的是:空间大小由最大类型来确定确定。
  3. 与int a; 中 类型名是int一个道理,这里union Test 在概念上就相当于 int。

2、共用体变量的名字:是共用体变量定义时候的名字,与 int a; 中变量名是a一个道理。

3、共用体变量的地址:显然这就是指向共用体变量的指针。值得注意的是,共用体变量的地址和它的各成员的地址都是同一个地址。

4、结构体变量的值:这里指的是共用体变量中成员变量的值,由于共用一块内存,它们的值也会相互影响。

3.共用体变量的定义(测一下占用空间)

1、知识点:定义的方式也和结构体一样,有标准的一种,不推荐的两种。同时,共用体变量的占用空间大小是成员变量里占用空间最大的确定的。

#include 
union Test
{
    char cdata;
    int idata;
    double ddata;
};
int main(int argc, char const *argv[])
{
    union Test t1;									   //t1就是union Test类型的共用体变量
    int sizeOfTest = sizeof(union Test);
    printf("共用体占用内存大小:%d\n", sizeOfTest);		//8,因为最大的成员占8个字节
    return 0;
}

2、两种不推荐的定义方式:

  1. 声明共用体,同时定义共用体变量:后面照样可以定义其他共用体变量,但这个方法尽量少用
    union Test
    {
        char cdata;
        int idata;
        double ddata;
    } t1, t2;

  2. 声明共用体时不写类型名,必须同时定义共用体变量:少用,因为后面无法再拿它来定义其他共用体变量。有时候我们这么用是在结构体中又套了一层共用体的情况(见习题1),那么内层的共用体可以不写类型名,因为我们不关心它。
    union
    {
        char cdata;
        int idata;
        double ddata;
    } t1, t2;

4.如何引用共用体变量中的成员变量(测一下地址)

与结构体一样,都是通过点运算符'.'。共用体变量名.成员变量名

1、知识点:共用体变量中所有成员的地址都相同

C的实用笔记43——共用体/联合体_第1张图片

 

#include 
union Test
{
    char cdata;
    int idata;
    double ddata;
};
int main(int argc, char const *argv[])
{
    union Test t1;
    printf("ti的地址   :0x%p\n", &t1);
    printf("cdata的地址:0x%p\n", &t1.cdata);
    printf("idata的地址:0x%p\n", &t1.idata);
    printf("ddata的地址:0x%p\n", &t1.ddata);
    return 0;
}

2、知识点:由于共用一块内存,所以给一个共用体变量中的成员变量赋值,其他成员变量的值会被覆盖。(根据变量值是从低地址开始存放的特点,可以自己计算一下覆盖后是什么值)

 

#include 
union Test
{
    char cdata;
    int idata;
    double ddata;
};
int main(int argc, char const *argv[])
{
    union Test t1;
    t1.idata = 10;
    t1.cdata = 'a';							//'a'会把10给覆盖掉,很明显的是'a'的ASCII码是97
    printf("idata=%d\n", t1.idata);
    t1.idata = 0x12345678;
    t1.cdata = 0xcc;                        //cc会把78给覆盖掉
    printf("idata=0x%x\n", t1.idata);    
    return 0;
}

5.共用体变量的初始化(只能给其中一个成员初始化)

1、知识点:如果给结构体变量初始化,那么只有第一个值有效,后面的均无效(这里没有覆盖)。且运行时会警告你有多余元素。

C的实用笔记43——共用体/联合体_第2张图片

 

#include 
union Test
{
    char cdata;
    int idata;
    double ddata;
};
int main(int argc, char const *argv[])
{
    union Test t1 = {'a', 10, 10.5};			只有第一个值'a'是有效的,后面均无效,且报错
    printf("cdata=%c\n", t1.cdata);
    printf("idata=%d\n", t1.idata);
    printf("ddata=%lf\n", t1.ddata);
    return 0;
}

6.习题

代码心得:

  1. 涉及到前后多个键盘输入时,要格外注意scanf、gets这些函数特点,判断它们:能否跳过第一个空格、回车、Tab键?能否吃掉输入结束的回车键?
  2. 涉及到输入时,如果你程序中有地方写错了,程序崩溃且不报错,那么就用gdb测试,①如果发现段错误就可能是没加取地址符号;②如果出现了一些看不懂的报错信息,那么多半是scanf中的占位符使用出错,比如说把%符号写成了&等其他符号;③更离谱的情况是,你输入的数据和占位符不匹配。
  3. 涉及到输出时,如果你程序中有地方写错了,程序崩溃且不报错,那么就用gdb测试,如果输出结果不对,那么多半是printf中的占位符和输出类型不匹配,比如说将字符型输出时,你却用%s。程序就会崩溃,但是用gdb测试就能看出确实写错了。

习题1:

 

  1. 思路:结构体中有联合体(同一个表格中有两类群体,导致表格中某列的数据类型不能统一,但是又舍不得浪费内存)。我们发现:对于学生和老师来说,性别、号码、性别、职业这四项是相同的(通用的,老师或者学生的这些数据的类型是一致的),不同点在于班级和职务(学生的班级是整型的,而老师的职务是字符串型的)。所以定义一个结构体,成员列表中有性别、号码、性别、职业;再定义一个共用体,成员列表中有班级和职务;最后把共用体变量作为结构体成员列表中的一员,也就是放在一个表格中处理。初始化这个表格的突破口:通过职业这个成员变量,确定这个人是老师还是学生,然后把共用体变量给初始化了,是学生就输入班级,是老师就输入职务,其他字段需要的话也可以初始化。
    声明一个结构体(内含共用体):
    struct Person
    {
        char sex;
        char career;
        char phone[12];
        char name[32];
        union 						//共用体的类型名可以不写,因为不关心
        {
            int class;
            char subject[12];
        } mes;
    };
    1. 定义一个结构体数组,同一个表格中有学生和老师两类群体,不妨设为: struct Person p[3];
    2. 用sizeof关键字计算出结构体数组长度,保存在变量len中: int len = sizeof(p) / sizeof(p[0]);
    3. for循环(注意这里不写表达式3),代表结构体数组下标(第i个人)的变量i从0开始, 

  2. 代码:
    #include 
    struct Person
    {
        char sex;
        char career;
        char phone[12];
        char name[32];
        union 
        {
            int class;
            char subject[12];
        } mes;
    };
    int main(int argc, char const *argv[])
    {
        struct Person p[3];     //结构体数组,同一个表格中有学生和老师两类群体
        int i;
        int len = sizeof(p) / sizeof(p[0]);
        for(i=0; i

你可能感兴趣的:(c语言)