当前位置: 首页 > news >正文

15_结构体联合与枚举_组织复杂数据

结构体、联合与枚举:组织复杂数据

一、本篇文章要解决什么问题

前面你学过的数据类型都是"单个"的:一个 int、一个 double、一个 char。但现实中很多数据是"打包"在一起的——比如一个学生的信息包括学号(int)、姓名(char 数组)、成绩(double),你不能用三个独立的变量随便放着,因为"张三的学号"和"李四的成绩"之间没有关联。

这篇文章帮你搞定三件事:

  1. struct 怎么把不同类型的数据打包成一个整体
  2. 怎么通过.->访问结构体成员
  3. union 和 enum 分别在什么场景下用

二、先用一个简单例子理解

2.1 档案袋的故事

你去学校教务处,每个学生有一个档案袋,袋子上写着名字,里面装着:学号条、成绩单、体检表。不同的材料类型不同(数字、文字、表格),但都装在一个袋子里,形成一个整体。

这个"档案袋"就是结构体(struct)——把不同类型的数据打包在一起,起一个名字,当作一个整体来传递。

2.2 union 就是"一物多用"的格子

一个储物柜的格子,今天放书包,明天放篮球。同一块空间,不同时间可以存不同类型的东西——这就是联合(union)

2.3 enum 就是"给数字起个好记的名字"

红灯=0、绿灯=1、黄灯=2——这就是枚举(enum)。用RED比用0更可读。


三、核心知识点讲解

3.1 struct 的定义和使用

#include<stdio.h>#include<string.h>structStudent{intid;// 学号charname[20];// 姓名doublescore;// 成绩};intmain(void){structStudentstu1;// 定义一个结构体变量stu1.id=1001;strcpy(stu1.name,"Zhang");stu1.score=95.5;printf("学号:%d\n",stu1.id);printf("姓名:%s\n",stu1.name);printf("成绩:%.1f\n",stu1.score);return0;}

运行结果:

学号:1001 姓名:Zhang 成绩:95.5

定义时直接初始化:

structStudentstu2={1002,"Li",88.0};

图15-1 结构体内存布局图:帮助理解结构体成员在内存中的排列。

3.2 结构体数组——一个班的学生

structStudentclass[3]={{1001,"Zhang",95.5},{1002,"Li",88.0},{1003,"Wang",76.5}};for(inti=0;i<3;i++){printf("%d %s %.1f\n",class[i].id,class[i].name,class[i].score);}

图15-2 结构体数组示意图:帮读者理解结构体数组的连续存储。

3.3 结构体指针——用 -> 访问成员

structStudentstu={1001,"Tom",90.0};structStudent*p=&stu;// 两种访问方式等价:printf("%d\n",(*p).id);// 先解引用再取成员——括号必须有!printf("%d\n",p->id);// 箭头运算符——更简洁

.->的区别.用于结构体变量,->用于结构体指针。p->member等价于(*p).member。初学者常把这两个搞混——看到指针就用->,看到变量就用.

图15-3 . 和 -> 运算符的使用场景图:让初学者记住"变量用点、指针用箭头"。

3.4 联合 union——同一块空间的不同解读

#include<stdio.h>unionData{inti;doubled;charc;};intmain(void){unionData u;u.i=65;printf("u.i = %d (占用 %u 字节)\n",u.i,(unsignedint)sizeof(u.i));u.c='A';printf("u.c = %c\n",u.c);// 注意:此时 u.i 的值已经被覆盖了——因为 i 和 c 共用同一块空间printf("整个 union 大小:%u 字节\n",(unsignedint)sizeof(u));// sizeof(union Data) 等于最大成员的大小return0;}

union 所有成员共享同一块内存空间,union 的大小等于其最大成员的大小。同一时间只能使用一个成员——你写入一个成员,其他成员的值就被覆盖了。

图15-4 union 和 struct 内存占用对比图:一目了然地展示 union 的 “共享空间” 特性。

3.5 枚举 enum——给整数起别名

#include<stdio.h>enumColor{RED,GREEN,BLUE};// RED=0, GREEN=1, BLUE=2enumStatus{OK=200,NOT_FOUND=404,ERROR=500};intmain(void){enumColorc=RED;printf("RED = %d\n",c);// 输出 0enumStatuss=NOT_FOUND;printf("NOT_FOUND = %d\n",s);// 输出 404return0;}

如果不手动指定值,枚举从 0 开始递增。也可以手动赋任意值。


四、完整代码示例

一个"学生信息管理"的基础版本,用结构体数组存储数据,用函数指针选择操作:

#define_CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<string.h>#defineMAX_STUDENTS50#defineNAME_LEN30structStudent{intid;charname[NAME_LEN];doublescore;};// 打印单个学生voidprintStudent(conststructStudent*s){printf("学号:%d 姓名:%-10s 成绩:%.1f\n",s->id,s->name,s->score);}// 打印所有学生voidprintAll(conststructStudentarr[],intcount){printf("\n===== 学生列表(共 %d 人)=====\n",count);for(inti=0;i<count;i++){printf("[%d] ",i+1);printStudent(&arr[i]);}}intmain(void){structStudentstudents[MAX_STUDENTS]={{1001,"Zhang",95.5},{1002,"Li",88.0},{1003,"Wang",76.5}};intcount=3;intchoice;do{printf("\n1. 显示所有学生\n");printf("2. 添加学生\n");printf("0. 退出\n");printf("请选择:");scanf("%d",&choice);switch(choice){case1:printAll(students,count);break;case2:if(count>=MAX_STUDENTS){printf("学生已满!\n");break;}printf("请输入学号、姓名、成绩:");scanf("%d %19s %lf",&students[count].id,students[count].name,&students[count].score);count++;printf("添加成功!\n");// 注意:%s 遇到空格就停,所以姓名不能含空格。// 如需支持"Zhang San"这类姓名,应改用 fgets 读取整行break;case0:printf("再见!\n");break;default:printf("无效选择\n");}}while(choice!=0);return0;}

五、运行结果

1. 显示所有学生 2. 添加学生 0. 退出 请选择:1 ===== 学生列表(共 3 人)===== [1] 学号:1001 姓名:Zhang 成绩:95.5 [2] 学号:1002 姓名:Li 成绩:88.0 [3] 学号:1003 姓名:Wang 成绩:76.5 1. 显示所有学生 2. 添加学生 0. 退出 请选择:2 请输入学号、姓名、成绩:1004 Zhao 82.0 添加成功! 1. 显示所有学生 2. 添加学生 0. 退出 请选择:0 再见!

六、代码逐行解析

结构体作为函数参数——传指针而非传值:

voidprintStudent(conststructStudent*s)

为什么不直接传struct Student s?因为结构体可能很大(如果有很多字段),值传递会完整复制一份——既慢又浪费内存。传指针只复制 4 或 8 字节的地址。const保证函数不会修改原始数据。

结构体数组成员访问:

students[count].id

students[count]是数组中的一个结构体变量,.id访问它的成员。如果要写成指针形式:(students + count)->id

do while 菜单循环:

do{...}while(choice!=0);

菜单至少显示一次,用户选 0 才退出——这是典型的 do while 场景。


七、初学者常见错误

错误1:忘记 struct 关键字(C 中不能省略)

// C 语言中structStudentstu;// 正确Student stu;// 错误(除非用了 typedef,见第 16 篇)

错误2:结构体指针用 . 而不是 ->

structStudent*p=&stu;p.name// 错误!p 是指针,用 -> 或 (*p).namep->name// 正确

错误3:用 == 比较两个结构体

structStudents1={...},s2={...};if(s1==s2){...}// 编译错误!结构体不能直接用 == 比较// 需要逐个成员比较

错误4:union 同时使用多个成员

unionData u;u.i=65;u.c='A';// u.i 的值现在无效了!不要同时依赖两个成员

错误5:enum 的值被当成字符串

enumColor{RED,GREEN};printf("%s\n",RED);// 错误!输出的是整数 0,不是 "RED"// 需要手动维护名称数组来转换

八、练习题

练习题1:分数统计

定义结构体struct Score { double chinese; double math; double english; }。用户输入 3 科成绩,程序计算总分和平均分,存入结构体并输出。

练习题2:按成绩排序

在完整代码示例的学生数组中,按成绩从高到低排序并输出。用冒泡排序,交换整体结构体(结构体可以直接赋值:struct Student temp = arr[i]; arr[i] = arr[j]; arr[j] = temp;)。

练习题3:用 enum 表示星期

定义一个enum Weekday { MON=1, TUE, WED, THU, FRI, SAT, SUN }。用户输入 1~7 的数字,程序输出对应的星期名称。


九、本篇总结

  1. struct 把不同类型数据打包,作为一个整体使用。访问成员用.(变量)或->(指针)
  2. 结构体数组适合批量管理相同结构的数据(如一个班的学生)
  3. union 成员共享同一块内存,大小等于最大成员;同时只能用其中一个
  4. enum 给整数常量起好记的名字,提高代码可读性
  5. 函数传结构体建议用指针,避免大量数据复制

http://www.jsqmd.com/news/881061/

相关文章:

  • Codex入门17-上下文管理(高手秘技:如何让AI精准理解你的百万行大型项目)
  • 医疗AI入门实战:用Python从MIMIC-CXR数据集中提取X光图像和诊断报告(附完整代码)
  • 避坑指南:在Ubuntu 22.04和服务器上成功编译SoftGroup点云分割模型(含gcc降级、sparsehash头文件修复)
  • 非结构化资料智慧解析应用方案(2026版)
  • Codex入门18-批量文件操作(效率神器:一句话批量重命名、格式化、清理几百个文件)
  • Unity 避免Text组件每行开头不是字符和空格,适配不同分辨率
  • 2026年4月线束设备公司口碑推荐,线束设备/剥线机/端子机,线束设备实力厂家哪家靠谱 - 品牌推荐师
  • 告别SSH断连焦虑:手把手教你用Screen在Linux后台挂起任务(含源码编译避坑)
  • 给客户打电话经常被挂?电话号码企业认证来帮忙
  • 【Linux:文件】Linux 动静态库详解::制作、使用、原理与实战
  • Codex入门19-数据库操作(解放双手:用自然语言写SQL、建表和数据迁移)
  • Deep Clustering of Tabular Data by Weighted Gaussian Distribution Learning——基于加权高斯分布学习的表格数据深度聚类
  • qemu和gcc编译
  • 从单用户到团队协作:给你的Ubuntu服务器配置多用户SSH访问权限(附sudo权限管理)
  • AI agent案例汇总:基于 LangGraph 的智能对话 Agent 实现
  • 文章三:Elasticsearch 集群恢复和索引分布
  • 2026年当前,上海别墅大宅新风系统可靠服务商深度解析 - 2026年企业推荐榜
  • 机器学习数据集详解,公开免费数据集获取渠道汇总
  • Try和expect的正确使用方式
  • 连锁董事网络指标数据(2001-2024)
  • 2026电工杯数学建模竞赛A题论文、代码、数据
  • 数据结构:线性表和顺序表
  • 2026槽式电缆桥架优质推荐指南:网格电缆桥架、铝合金走线架、不锈钢电缆桥架、北京电缆桥架厂家、托盘式电缆桥架选择指南 - 优质品牌商家
  • Claude Code 在安装vscode插件时遇到的问题。
  • 告别图形界面!5个CUPS命令行技巧,让你在Linux终端高效管理打印机
  • 2026微型舵机优质推荐榜:小型舵机/尾翼用方扁舵机/工业舵机/德晟舵机/数字舵机/无人机舵机/无刷舵机/最小的舵机/选择指南 - 优质品牌商家
  • 2026电工杯数学建模竞赛A题论文、代码、数据(改进)
  • # 网页设计学习感悟
  • 朝晖玻璃钢:玻璃钢保温水箱/玻璃钢消防水箱/玻璃钢罐化粪池/碳钢水箱/立式不锈钢水箱/组合式玻璃钢水箱/雨水一体化提升泵站/选择指南 - 优质品牌商家
  • 别再手动下载DLL了!用Windows自带工具SFC/SCANNOW一键修复kernel32.dll错误