【基础知识】结构体(struct)和联合体(union)

1. 结构体(Struct)

        在 C 语言中,结构体是一种自定义的复合数据类型,允许将不同数据类型的变量组合成一个单一的实体。结构体可以包含多个成员,每个成员可以是不同的数据类型,如整数、浮点数、字符、数组等。

        结构体的定义通常在函数外部,并且在函数内部可以声明和使用结构体类型的变量。结构体的定义包含了结构体的名称和结构体成员的列表,每个成员都有一个名称和一个数据类型。结构体的成员可以通过成员运算符(.)来访问。

以下是一个简单的 C语言 结构体的示例:

#include <stdio.h>

// 定义一个名为Student的结构体
struct Student {
    int roll_no; // 学号
    char name[50]; // 姓名
    int age; // 年龄
    float score; // 分数
};

int main() {
    // 声明并初始化一个Student类型的结构体变量
    struct Student student1 = {101, "Alice", 20, 95.5};

    // 访问结构体成员并输出
    printf("Roll No: %d\n", student1.roll_no);
    printf("Name: %s\n", student1.name);
    printf("Age: %d\n", student1.age);
    printf("Score: %.2f\n", student1.score);

    return 0;
}

1.1 C++ 结构体和 C 语言结构体的区别

        C++ 中的结构体和 C 语言中的结构体在语法上基本上是一致的,但在 C++ 中,结构体还具有类的特性,包括封装、继承和多态等,从而与 C 语言中的结构体有一些区别。

主要区别如下:

  • 成员函数:C 的结构体内不允许有函数存在,C++ 中的结构体可以包含成员函数,且允许该函数是虚函数,这是与 C 语言中的结构体最大的不同之一。C++ 中的结构体可以像类一样定义成员函数,可以在结构体内部绑定成员函数的实现,并在结构体对象上调用这些成员函数。
  • 访问控制:C++ 中的结构体可以使用 public、protected、private 关键字来限制成员变量的访问权限,从而实现封装性;而 C 语言中的结构体对内部成员变量的访问权限只能是 public,可以在任何地方被访问。
  • 继承:C++ 中的结构体可以通过继承从其他结构体或派生类,从而实现继承的特性,包括单继承和多继承;而 C 语言中的结构体没有继承的概念。
  • 构造函数和析构函数:C++ 中的结构体可以定义构造函数和析构函数,用于对象的初始化和清理操作;C 语言中的结构体没有构造函数和析构函数的概念。
  • 默认访问修饰符:C++ 中的结构体成员默认是 private 访问修饰符,而 C 语言中的结构体成员默认是 public 访问修饰符。
  • C 中使用结构体需要加上 struct 关键字,或者对结构体使用 typedef 取别名,而 C++ 中可以省略 struct 关键字直接使用.

1.2 结构体的对齐方式

        结构体对齐根据最大类型长度对齐。结构体大小一定是最大成员的整数倍

对齐规则:

  • 结构体变量的首地址能够被其最宽基本类型成员的大小所整除

        编译器在给结构体开辟空间时,首先找到结构体中最宽的基本数据类型,然后寻找内存地址能被该基本数据类型所整除的位置,作为结构体的首地址。将这个最宽的基本数据类型的大小作为上面介绍的对齐摸数。

  • 结构体每个成员相对结构体首地址的偏移量(offset)都是成员大小的整数倍

        如有需要编译器在成员之间加上填充字节作为结构体的一个成员开辟空间之前,编译器首先检查预开辟空间的首地址相对于结构体首地址的偏移是否是本成员大小的整数倍,若是,则存放本成员,反之,则在成员和上一个成员之间填充一定的字节,以达到整数倍的要求,也就是将预开辟空间的首地址后移几个字节。

  • 结构体的总大小为结构体最宽基本类型成员大小的整数倍

        如有需要编译器会在最末一个成员之后加上填充字节,结构体总大小是包括填充字节,最后一个成员满足上面两条以外,还必须满足第三条,否则就必须在最后填充几个字节以达到本条要求。

例如:

//1.
struct A
{
    char c1;    //大小 (char)1 + 3(填充数)
    int i;      //大小 (int)4
    char c2;    //大小 (char)1 + 3(填充数)
}
//该结构体对齐数为 4(int),则结构体大小为 
//(1 + 3)+ 4 +(1+3)=12




//2.
struct A
{
    char c1;    //大小 (char)1 + 3(填充数)
    int i;      //大小 (int)4
    char c2;    //大小 (char)1
    char c3[5];  大小 (char)1 * 5 + 2(填充数),
    //因为是以4对齐,c2为1个字节,还剩3个位置给c3,
    //然后c3的最后两个字节位置再开辟下一行,新一行没有满足4,则再加2个填充数。
}
//该结构体对齐数为 4(int),加上一个char类型的数组
//可以看作有5个char类型存入内存中,则结构体大小为:
//(1+3)+ 4 + 1 + 5 + 2 =16





//3.
struct A
{
    char c1;//1+3
    int i;//4
    char c2;//1+7
    double c[5];//40
};
//该结构体对齐数为 8(double),加上一个double类型的数组
//可以看作有5个double类型存入内存中,则结构体大小为:
//(1+3)+ 4 + 1 + 7 + (8*5) =56



2. 联合体(Union)

        在 C 语言中,联合体是一种特殊的数据结构,可以在内存中共享同一段存储空间来存储不同类型的数据。与结构体类似,联合体也是一种用户自定义的数据类型,可以包含多个不同类型的成员变量。

        联合体的定义使用关键字‘union’,后面紧跟联合体的名称和一对花括号,括号中定义了联合体的成员变量,每个成员变量有自己的名称和数据类型。

#include <stdio.h>

// 定义一个联合体
union Data {
    int i;
    float f;
    char c;
};

int main() {
    union Data data; // 声明一个联合体变量data

    data.i = 42; // 给联合体的整数成员赋值
    printf("data.i = %d\n", data.i); // 输出整数成员的值

    data.f = 3.14; // 给联合体的浮点数成员赋值
    printf("data.f = %.2f\n", data.f); // 输出浮点数成员的值

    data.c = 'A'; // 给联合体的字符成员赋值
    printf("data.c = %c\n", data.c); // 输出字符成员的值

    // 注意:联合体的不同成员共享同一块内存空间,赋值一个成员会影响其他成员的值
    printf("data.i = %d, data.f = %.2f, data.c = %c\n", data.i,data.f, data.c);
    //data.i = 1078523201, data.f = 3.14, data.c = A

    return 0;
}

2.1 联合体特性

  • 联合体是一个结构
  • 它的所有成员相对于基地址的偏移量都为 0
  • 次结构空间要大到足够容纳最“”的成员;
  • 其对齐方式要适合其中所有的成员;

3. 结构体和联合体的区别

        (1)结构体中的每个成员都占用独立的内存空间,而联合体中的所有成员共享同一块内存空间。这意味着,在联合体中只有一个成员变量能够同时存储值,而其他成员变量会被覆盖;

        (2)结构体的内存占用大小等于所有成员的内存大小之和,而联合体的内存占用大小等于其最大成员的内存大小,因此,联合体在内存占用上通常比结构体更节省;

        (3)结构体的成员可以同时被访问和修改,而联合体的成员只能同时访问和修改一个成员。这是因为联合体的成员共享同一块内存空间,修改其中一个成员会影响其他成员的值。

        (4)结构体的成员在内存中按照定义的顺序依次排列,而联合体的所有成员共享同一块内存空间,因此只有一个成员可以存储有效值;

        (5)结构体的初始化可以为每个成员分别赋值,而联合体的初始化只能对其中一个成员赋值。

 

  • 15
    点赞
  • 103
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
结构体的定义和访问结构体成员: 结构体是由一组不同类型的变量组成的数据类型,可以通过定义一个结构体变量来使用结构体,访问结构体成员使用"."操作符,例如: ``` struct Person { char name[20]; int age; float height; }; Person p; strcpy(p.name, "Tom"); p.age = 20; p.height = 1.75; ``` 以上代码定义了一个Person结构体,包含了char类型的name、int类型的age和float类型的height三个成员变量,然后定义了一个Person类型的变量p,使用strcpy函数给p.name赋值,给p.age和p.height赋值。 联合体的定义和访问联合体成员: 联合体是一种数据类型,它允许在同一内存位置存储不同的数据类型。联合体的定义方式与结构体相似,但是联合体中的成员变量共享同一块内存空间,因此联合体中只能同时存储一个成员变量的值,访问联合体成员使用"."操作符,例如: ``` union Data { int i; float f; char str[20]; }; Data d; d.i = 10; cout << d.i << endl; // 输出10 d.f = 3.14; cout << d.f << endl; // 输出3.14 strcpy(d.str, "hello"); cout << d.str << endl; // 输出hello ``` 以上代码定义了一个Data联合体,包含了int类型的i、float类型的f和char类型的str三个成员变量,然后定义了一个Data类型的变量d,首先给d.i赋值,然后给d.f赋值,最后使用strcpy函数给d.str赋值。由于联合体中的成员变量共享同一块内存空间,因此d.i和d.f的值会互相覆盖,最后输出d.str时,输出的是d.str中存储的值。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值