C 语言|自定义类型:结构体、联合体与枚举 —— 学习笔记
2026/9/8 15:54:19 网站建设 项目流程

C语言当中,结构体、联合体与枚举属于自定义的数据类型,内存排布、参数传递等方面存在不少容易混淆的知识点。本文就结构体、联合体、枚举的基础概念、内存特征以及基本用法展开整理,记录学习当中的理解。

文章目录

    • 结构体struct
      • 什么是结构体
      • 结构体内存对齐
      • 结构体传参
    • 联合体(共同体)union
      • 什么是联合体
      • 联合体大小及与结构体的区别
    • 枚举enum
      • 什么是枚举
      • 枚举的使用

结构体struct

什么是结构体

struct可以把多种不同类型的数据打包在一起,用来描述一个对象。

示例一:结构体定义、创建变量、初始化,访问成员

#include<stdio.h>// 定义结构体模版,只是描述格式,不开辟内存structStu{charname[20];// 名字intage;// 年龄charsex[5];// 性别charid[20];// 学号};intmain(){// 按顺序给成员赋值初始化structStus1={"张三",20,"男","202308001"};// C99写法,指定成员赋值,顺序可以随便写structStus2={.age=18,.name="list",id="202308001",sex="女"};// 普遍结构体变量,用. 访问成员s1.age=21;// 结构体指针,用 -> 访问成员structStu*ps=&s1;ps->age=22;return0;}

示例二:typedef 给结构体起别名

#include<stdio.h>// typedef 给结构体起别名,以后不用重复写structtypedefstructStu{charname{20};intage;}Student;intmain(){Student s;s.age=19;return0;}

结构体内存对齐

计算结构体占用内存大小需要遵守三条对齐规则,目的是方便CPU读取数据。
1. 每个成员存放地址,必须是自身类型大小的倍数。
2. 结构体总大小,必须等于内部最大成员大小的倍数。
3. 不满足上面,编译器自动补空余字节,空余字节不能存数据。


特殊#pragma pack预处理指令,可以修改编译器默认对齐方式。

#include<stdio.h>// 设置结构体的最大对齐数为1,取消内存填充#pragmapack(1)structS{charc1;// 1 1 1inti;// 4 1 4charc2;// 1 1 1};// 恢复编译器原本默认对齐数,后面代码不受pack(1)影响#pragmapack()intmain(){// 总大小:1 + 4 + 1 = 6字节printf("sizeof(struct S)=%d\n",sizeof(structS));return0;}

结构体传参

两种传参方式:值传递、地址传递。

函数传参时,参数是压栈处理,会占用栈空间。如果结构体对象本身规模很大,参数压栈的系统开销就会比较大,容易导致栈溢出。结论:结构体传参优先传结构体的地址。

#include<stdio.h>structS{intdata[5];intnum;};// 值传递:把整个结构体复制一份传给函数// 函数修改的是复制出来的副本,不会改外面原数据;结构体大的时候开销大,存在栈溢出风险voidPrint1(structSs){inti=0;for(i=0;i<5;i++){printf("%d ",s.data[i]);}printf("\n%d\n",s.num);}// 地址传递:只传结构体地址,不复制全部数据,开销小,规避栈溢出问题// const:限制函数,不让修改外面原始数据;去掉const就可以修改原结构体voidPrint2(conststructS*ps){inti=0;for(i=0;i<5;i++){printf("%d ",ps->data[i]);}printf("\n%d\n",ps->num);}intmain(){structSs={{1,2,3,4,5},100};Print1(s);Print2(&s);return0;}

联合体(共同体)union

什么是联合体

关键字union,里面可以放多种不同类型变量,全部共用同一块内存。改其中一个成员,别个成员就会被覆盖。

#include<stdio.h>// 定义联合体类型unionUn{charc;inti;};intmain(){unionUn un={0};// 创建联合体变量un.i=0x11223344;// 给int成员赋值printf("修改前 i = %#x\n",un.i);un.c=0x55;// 修改char,会覆盖 int 的低字节(共用内存)printf("修改后 i = %#x\n",un.i)printf("联合体大小:%d\n",sizeof(un));return0;}

联合体大小及与结构体的区别

计算规则

  1. 联合体最少要等于最大那个成员的字节。
  2. 联合体的最大对齐数 = 联合体中最大基础类型成员的字节数
  3. 如果这个大小不满足最大对齐数的倍数,后面补空字节凑够倍数。

与结构体的区别


核心对比

  1. 内存:结构体每个成员各占一块内存;联合体全部成员共用一块内存
  2. 大小:结构体:所有成员字节相加,再补对齐空位;联合体:取最大成员大小,再补对齐空位
  3. 使用:结构体所有成员可以同时用;联合体同一时间只能用其中一个成员

枚举enum

什么是枚举

枚举用关键字enum表示,顾名思义就是一 一列举,把变量所有可能的取值全部罗列出来。
像星期,性别,三原色,取值有限,适合使用枚举。

规则:

  1. 不给常量写数值,第一个默认是0,后面依次+1
  2. 枚举本质是整型常量,底层占4字节。
  3. 枚举常量不可以被赋值修改。

示例

//星期enumDay{Mon,Tues,Wed,Thur,Fri,Sat,Sun};//性别enumSex{MALE,FEMALE,SECRET};//三原色enumColor{RED,GREEN,BLUE};

枚举的使用

作用:替代程序中含义模糊的魔法数字,提升代码可读性,同时限制变量只能使用列举出来的合法值,减少程序出错。

示例

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询