别再混淆 struct/union/enum!看完这篇彻底搞懂构造数据类型

C语言 结构体、共用体、枚举知识点整理

三者都属于构造数据类型,是用户自己组合出来的数据类型,不是C语言内置基础类型(char/int/float等)。

一、结构体 struct

1. 声明语法

struct 结构体名
{
    数据类型 成员名1;
    数据类型 成员名2;
    //更多成员
};  //分号不能省略
  • 可以省略结构体名,得到匿名结构体,只能紧跟着定义变量,不能后续复用。
  • 结构体内部可以嵌套别的结构体。

2. 定义变量

//方式1:先声明类型,再定义变量
struct Date
{
    int year;
    int mon;
    int day;
};
struct Date d1;

//方式2:声明同时定义变量
struct Date
{
    int year;
    int mon;
    int day;
}d2;

3. 初始化

//全部初始化
struct Date d1 = {2026,8,18};

//指定成员初始化(推荐)
struct Date d2 = {.year=2026,.day=18};

4. 成员访问

  1. 结构体变量 . 成员名:普通结构体变量访问
d1.year = 2026;
  1. 结构体指针 -> 成员名:结构体指针访问
struct Date *p = &d1;
p->year = 2026;

5. 内存存储(内存对齐)

  1. 每个成员存储在自身字节大小的整数倍地址。
  2. 结构体总大小 = 最大成员字节数的整数倍,中间会填充对齐字节。
  3. 可以用#pragma pack(n)强制修改对齐字节。
#pragma pack(1)  //按1字节对齐,关闭对齐
struct S{
    int a;
    char b;
};
#pragma pack()   //恢复默认对齐

6. 函数传参

  1. 值传递:拷贝整个结构体,开销大,函数内修改不会影响外部原变量。
  2. 传地址(结构体指针):只传地址,效率高;函数内可以修改外部结构体成员。

7. 结构体数组

数组每个元素都是结构体类型,数组[下标].成员访问成员。


二、共用体(联合体) union

1. 声明语法

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

2. 核心特点⭐

  1. 所有成员共享同一块内存空间,同一时刻只能有效使用其中一个成员。
  2. 共用体占用内存大小:等于占用字节最大的那个成员的大小
  3. 存储结果取决于最后一次赋值的成员,给一个成员赋值会覆盖其他成员数据。

3. 变量定义、成员访问

和结构体语法完全一样:

  • 变量访问:union变量.成员
  • 指针访问:union指针->成员

4. 典型用途:判断系统大小端

union S{
    int a;
    char b;
};
union S tmp;
tmp.a = 1;
if(tmp.b){
    printf("小端\n");
}else{
    printf("大端\n");
}

小端:低地址存低字节;大端:低地址存高字节。


三、枚举 enum

1. 声明语法

enum 枚举名
{
    枚举常量1,
    枚举常量2,
    枚举常量3
};
  • {}内部是整型枚举常量,不是变量,不能写数据类型。
  • 常量之间逗号分隔。

2. 枚举常量赋值规则

  1. 如果不给值:默认从0开始,后续依次+1
enum Color{RED,GREEN,BLUE}; 
// RED=0,GREEN=1,BLUE=2
  1. 指定某一个常量的值,后面常量自动递增1
enum Week{MON=1,TUE,WED,THU};
// MON=1,TUE=2,WED=3,THU=4

3. 枚举变量

enum Week w = MON;

枚举变量本质就是整型,可以直接和整数比较。

4. 使用规范

枚举常量习惯大写,区分普通变量。


四、typedef给构造类型重命名

typedef:给已有数据类型起别名,不是创造新类型

//结构体别名
typedef struct Student{
    char name[32];
    int score;
}STU_s;

//共用体别名
typedef union Data{
    int i;
    char c;
}DATA_u;

//枚举别名
typedef enum{
    ON,OFF
}STATE_e;

//使用别名定义变量,不用写struct/union/enum
STU_s s1;
DATA_u d1;
STATE_e st;

五、struct / union / enum 异同对比

对比项结构体 struct共用体 union枚举 enum
作用多个不同含义的数据同时保存到一起多个成员共享同一块内存,同一时刻只用一个成员定义一组整型符号常量,增加代码可读性
内存大小受内存对齐影响,≥所有成员字节总和等于最大成员的字节大小就是int大小,枚举本质是整型
成员内存关系每个成员拥有独立内存空间全部成员共用同一块内存空间没有成员变量,全部是整型常量
赋值所有成员可以同时保存有效数据修改一个成员,覆盖其他成员的数据只能给枚举变量赋值枚举常量,常量不能修改
典型场景描述一个事物的多项属性(学生信息、时间)节省内存、大小端检测,多类型复用空间状态标记、选项集合(开关、星期)

相同点

  1. 三者都是构造类型,需要先声明类型,再定义变量;
  2. 都支持typedef起别名;
  3. 声明的时候}后面必须带分号
  4. 都可以做函数参数、数组元素。

关键区别总结

  1. 结构体:成员互相独立,同时共存;
  2. 共用体:成员互相覆盖,互斥共存;
  3. 枚举:没有普通成员,只有一组整型符号常量。

补充易错点

  1. 结构体不要忘记最后的分号;
  2. union不要同时使用多个成员,只有最后赋值的成员有效;
  3. enum里面是常量,不能对枚举常量赋值;
  4. typedef只是别名,不是新类型;
  5. 结构体存在内存对齐,sizeof结果不等于成员简单相加。

struct、union、enum完整演示代码

#include <stdio.h>

//==================== 结构体 struct ====================
//声明结构体类型
struct Student
{
    char name[32];
    int age;
    int score;
};

//typedef给结构体起别名
typedef struct Date
{
    int year;
    int mon;
    int day;
}Date_s;

//结构体传参:传地址(推荐,效率高,可以修改外部变量)
void printStu(struct Student *p)
{
    printf("姓名:%s 年龄:%d 分数:%d\n", p->name, p->age, p->score);
    p->score = 99; //修改外部结构体成员
}

//==================== 共用体 union ====================
union Data
{
    int i;
    char c;
    float f;
};

//大小端检测共用体
typedef union EndianTest
{
    int a;
    char b;
}Endian_u;

//==================== 枚举 enum ====================
//枚举,默认从0开始
enum Color
{
    RED,
    GREEN,
    BLUE
};

//手动指定枚举起始值
typedef enum Week
{
    MON = 1,
    TUE,
    WED,
    THU,
    FRI,
    SAT,
    SUN
}Week_e;

int main(void)
{
    //---------- 结构体使用 ----------
    struct Student s1 = {"zhangsan", 18, 88};
    printStu(&s1);
    printf("修改后分数:%d\n", s1.score);

    //指定成员初始化
    Date_s d1 = {.year = 2026, .day = 18};
    printf("date:%d年%d月%d日\n", d1.year, d1.mon, d1.day);
    printf("结构体Student大小:%zu\n\n", sizeof(struct Student));

    //---------- 共用体使用 ----------
    union Data u1;
    u1.i = 100;
    printf("u1.i = %d\n", u1.i);

    u1.c = 'A';  //给c赋值,会覆盖i的数据
    printf("u1.c = %c , u1.i = %d\n", u1.c, u1.i);
    printf("共用体Data大小:%zu\n\n", sizeof(union Data));

    //大小端测试
    Endian_u et;
    et.a = 1;
    if(et.b == 1)
    {
        printf("本机:小端模式\n");
    }
    else
    {
        printf("本机:大端模式\n\n");
    }

    //---------- 枚举使用 ----------
    enum Color c = RED;
    printf("RED=%d GREEN=%d BLUE=%d\n", RED, GREEN, BLUE);

    Week_e w = WED;
    printf("WED = %d\n", w);

    if(w == WED)
    {
        printf("今天是周三\n");
    }

    return 0;
}

编译运行

gcc test.c -o a.out
./a.out

输出示例(小端机器)

姓名:zhangsan 年龄:18 分数:88
修改后分数:99
date:2026年0月18日
结构体Student大小:40

u1.i = 100
u1.c = A , u1.i = 65
共用体Data大小:4

本机:小端模式

RED=0 GREEN=1 BLUE=2
WED = 3
今天是周三

重点代码说明

  1. 结构体
  • 结构体指针->成员,普通变量用 .访问成员;
  • 传指针可以修改外部原始结构体;值传递会拷贝一份,修改不会影响外部。
  1. 共用体>

所有成员共用一块内存,对一个成员赋值,其他成员数据被覆盖

u1.i = 100;
u1.c = 'A'; //覆盖上面i的值
  1. 枚举
  • 枚举里面RED,GREEN常量,不能写RED=100;
  • 枚举变量本质就是int,可以直接做判断、比较。
  1. typedef
    typedef 原类型 别名,只是起别名,没有创造新的数据类型
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值