六安在线网,郑州关键词网站优化排名,大连成久建设工程有限公司,外发加工网官网这两周肝 C 语言课程设计#xff0c;从最初的 “影院票务管理系统” 魔改成了心心念念的 “铠甲勇士管理系统”#xff0c;踩了无数坑#xff1a;结构体字段混乱、文件读写乱码、链表遍历崩溃、搜索逻辑不灵活… 现在终于把核心功能跑通了#xff0c;这篇博客把完整代码和核…这两周肝 C 语言课程设计从最初的 “影院票务管理系统” 魔改成了心心念念的 “铠甲勇士管理系统”踩了无数坑结构体字段混乱、文件读写乱码、链表遍历崩溃、搜索逻辑不灵活… 现在终于把核心功能跑通了这篇博客把完整代码和核心思路分享出来纯纯大学生实战心得没有花里胡哨的理论全是能直接复用的干货。先说明核心思路我没有重新造轮子新建armor结构体而是直接复用原有movie结构体给它补充铠甲专属字段类型、属性、状态这样原有链表、文件操作逻辑不用大改只需要针对性补充新手也能快速上手。一、核心结构体设计最关键的一步先贴结构体定义这是整个系统的基础所有功能都围绕它展开#define _CRT_SECURE_NO_WARNINGS #include stdio.h #include stdlib.h #include string.h // 铠甲属性枚举火/水/雷/土/风 typedef enum { ATTR_FIRE, ATTR_WATER, ATTR_THUNDER, ATTR_EARTH, ATTR_WIND } MonsterAttr; // 铠甲状态枚举闲置/战斗中/维修中/破损 typedef enum { ARMOR_IDLE, ARMOR_IN_BATTLE, ARMOR_REPAIRING, ARMOR_DAMAGED } ArmorStatus; // 用户铠甲召唤人结构体 typedef struct user { int id; char name[50]; char password[50]; int isAdmin; // 0普通用户 1管理员 struct user* next; } user; // 铠甲结构体复用原movie结构体核心改造 typedef struct movie { int id; char title[50]; // 铠甲名称 float price; // 授权费用元/小时 char type[50]; // 铠甲类型攻击型/全能型/防御型 ArmorStatus status; // 铠甲状态 MonsterAttr attr; // 铠甲属性 struct movie* next; } movie; // 订单铠甲授权记录结构体 typedef struct order { int id; int userId; // 召唤人ID int movieId; // 铠甲ID char movieName[50]; // 铠甲名称 int quantity; // 授权时长小时 float totalPrice;// 总费用 int monsterId; // 讨伐怪兽ID0未讨伐 int battleResult;// 战斗结果1胜 0败 -1未战 struct order* next; } order; // 怪兽结构体铠一铠二经典怪兽 typedef struct monster { int id; char name[50]; int level; MonsterAttr attr; int danger; // 危险等级 int isDefeated; // 是否被封印1是 0否 struct monster* next; } monster; // 全局链表头指针 user* head NULL; movie* movieList NULL; user* currentUser NULL; order* orderList NULL; monster* monsterList NULL;二、核心功能代码直接复制就能用1. 文件存储与加载避免数据丢失课设必做这部分是我踩坑最多的地方重点是用 “标记 格式” 统一读写枚举类型转数字存储// 保存所有数据到文件 void save_to_file() { FILE* fp fopen(armor_system.txt, w); if (!fp) { printf(文件打开失败\n); return; } // 保存用户数据 user* p head; while (p) { fprintf(fp, USER %d %s %s %d\n, p-id, p-name, p-password, p-isAdmin); p p-next; } // 保存铠甲数据含新增的类型/属性/状态 movie* m movieList; while (m) { fprintf(fp, ARMOR %d %s %.2f %s %d %d\n, m-id, m-title, m-price, m-type, m-attr, m-status); m m-next; } // 保存订单数据 order* o orderList; while (o) { fprintf(fp, ORDER %d %d %d %s %d %.2f %d %d\n, o-id, o-userId, o-movieId, o-movieName, o-quantity, o-totalPrice, o-monsterId, o-battleResult); o o-next; } // 保存怪兽数据 monster* ms monsterList; while (ms) { fprintf(fp, MONSTER %d %s %d %d %d %d\n, ms-id, ms-name, ms-level, ms-attr, ms-danger, ms-isDefeated); ms ms-next; } fclose(fp); printf(数据保存成功\n); } // 从文件加载所有数据 void load_from_file() { FILE* fp fopen(armor_system.txt, r); if (fp NULL) { printf(无历史数据初始化默认怪兽列表...\n); initMonsterList(); return; } char type[10]; int id, isAdmin, userId, movieId, quantity, monsterLevel, monsterAttr, monsterDanger, isDefeated; int armorAttr, armorStatus, monsterId, battleResult; char name[50], password[50], title[50], movieName[50], armorType[50], monsterName[50]; float price, totalPrice; while (fscanf(fp, %s, type) ! EOF) { if (strcmp(type, USER) 0) { if (fscanf(fp, %d %s %s %d, id, name, password, isAdmin) 4) { user* newuser (user*)malloc(sizeof(user)); newuser-id id; strcpy(newuser-name, name); strcpy(newuser-password, password); newuser-isAdmin isAdmin; newuser-next head; head newuser; } } else if (strcmp(type, ARMOR) 0) { if (fscanf(fp, %d %s %f %s %d %d, id, title, price, armorType, armorAttr, armorStatus) 6) { movie* newmovie (movie*)malloc(sizeof(movie)); newmovie-id id; strcpy(newmovie-title, title); newmovie-price price; strcpy(newmovie-type, armorType); newmovie-attr (MonsterAttr)armorAttr; newmovie-status (ArmorStatus)armorStatus; newmovie-next movieList; movieList newmovie; } } else if (strcmp(type, ORDER) 0) { if (fscanf(fp, %d %d %d %s %d %f %d %d, id, userId, movieId, movieName, quantity, totalPrice, monsterId, battleResult) 8) { order* neworder (order*)malloc(sizeof(order)); neworder-id id; neworder-userId userId; neworder-movieId movieId; strcpy(neworder-movieName, movieName); neworder-quantity quantity; neworder-totalPrice totalPrice; neworder-monsterId monsterId; neworder-battleResult battleResult; neworder-next orderList; orderList neworder; } } else if (strcmp(type, MONSTER) 0) { if (fscanf(fp, %d %s %d %d %d %d, id, monsterName, monsterLevel, monsterAttr, monsterDanger, isDefeated) 6) { monster* newmonster (monster*)malloc(sizeof(monster)); newmonster-id id; strcpy(newmonster-name, monsterName); newmonster-level monsterLevel; newmonster-attr (MonsterAttr)monsterAttr; newmonster-danger monsterDanger; newmonster-isDefeated isDefeated; newmonster-next NULL; if (monsterList NULL) { monsterList newmonster; } else { monster* p monsterList; while (p-next ! NULL) p p-next; p-next newmonster; } } } } fclose(fp); if (monsterList NULL) initMonsterList(); printf(数据加载成功\n); }2. 铠甲搜索功能支持多维度搜索课设加分项这个函数是我优化最多的从只能搜名字改成支持按名称 / 类型 / 属性搜索核心是match标记变量的使用void searchMovie() { int searchType; char keyword[50]; printf( 铠甲搜索 \n); printf(1. 按铠甲名称搜索\n); printf(2. 按铠甲类型搜索攻击型/全能型等\n); printf(3. 按铠甲属性搜索火/水/雷等\n); printf(请选择搜索方式); scanf(%d, searchType); printf(请输入搜索关键词); scanf(%s, keyword); movie* p movieList; int found 0; printf(\n 铠甲搜索结果 \n); printf(铠甲ID\t名称\t\t授权价格\t类型\t\t属性\t\t状态\n); while (p ! NULL) { int match 0; switch (searchType) { case 1: // 按名称模糊匹配 match (strstr(p-title, keyword) ! NULL); break; case 2: // 按类型模糊匹配 match (strstr(p-type, keyword) ! NULL); break; case 3: // 按属性精确匹配 if (strcmp(keyword, 火) 0 || strcmp(keyword, 火属性) 0) match (p-attr ATTR_FIRE); else if (strcmp(keyword, 水) 0 || strcmp(keyword, 水属性) 0) match (p-attr ATTR_WATER); else if (strcmp(keyword, 雷) 0 || strcmp(keyword, 雷属性) 0) match (p-attr ATTR_THUNDER); else if (strcmp(keyword, 土) 0 || strcmp(keyword, 土属性) 0) match (p-attr ATTR_EARTH); else if (strcmp(keyword, 风) 0 || strcmp(keyword, 风属性) 0) match (p-attr ATTR_WIND); break; default: printf(搜索方式错误\n); return; } if (match) { found 1; printf(%d\t%s\t\t%.2f\t\t%s\t\t%s\t\t%s\n, p-id, p-title, p-price, p-type, p-attr ATTR_FIRE ? 火属性 : (p-attr ATTR_WATER ? 水属性 : (p-attr ATTR_THUNDER ? 雷属性 : (p-attr ATTR_EARTH ? 土属性 : 风属性))), p-status ARMOR_IDLE ? 闲置 : (p-status ARMOR_IN_BATTLE ? 战斗中 : (p-status ARMOR_REPAIRING ? 维修中 : 破损))); } p p-next; } if (found 0) { printf(未找到符合条件的铠甲\n); } printf(\n按任意键继续。。。\n); getchar(); getchar(); }3. 铠甲授权购票功能核心业务逻辑重点加了防护逻辑未登录不能买、铠甲状态异常不能买、时长不能为负新手一定要注意这些细节void buyTicket() { if (currentUser NULL) { printf(请先登录铠甲召唤系统\n); getchar(); getchar(); return; } browseMovies(); int armorId, hourNum; float totalPrice; printf(请输入申请授权的铠甲ID\n); scanf(%d, armorId); movie* p movieList; while (p ! NULL) { if (p-id armorId) { // 铠甲状态校验 if (p-status ARMOR_IN_BATTLE) { printf(【%s】正在战斗中暂时无法授权\n, p-title); getchar(); getchar(); return; } if (p-status ARMOR_DAMAGED) { printf(【%s】已破损维修完成前无法授权\n, p-title); getchar(); getchar(); return; } printf(选中铠甲%s\n, p-title); printf(铠甲类型%s | 属性%s\n, p-type, p-attr ATTR_FIRE ? 火属性 : (p-attr ATTR_WATER ? 水属性 : (p-attr ATTR_THUNDER ? 雷属性 : (p-attr ATTR_EARTH ? 土属性 : 风属性)))); printf(授权费用: %.2f 元/小时\n, p-price); printf(请选择授权时长小时\n); scanf(%d, hourNum); if (hourNum 0) { printf(授权时长必须大于0\n); getchar(); getchar(); return; } totalPrice p-price * hourNum; order* neworder (order*)malloc(sizeof(order)); if (neworder NULL) { printf(授权失败系统资源不足\n); getchar(); getchar(); return; } // 生成订单ID int maxOrderId 0; order* o orderList; while (o ! NULL) { if (o-id maxOrderId) maxOrderId o-id; o o-next; } neworder-id maxOrderId 1; neworder-movieId p-id; strcpy(neworder-movieName, p-title); neworder-totalPrice totalPrice; neworder-quantity hourNum; neworder-userId currentUser-id; neworder-monsterId 0; neworder-battleResult -1; neworder-next orderList; orderList neworder; printf(\n); printf(铠甲授权成功\n); printf(召唤人%s\n, currentUser-name); printf(授权铠甲%s\n, p-title); printf(授权时长%d 小时\n, hourNum); printf(总费用%.2f 元\n, totalPrice); printf(\n); save_to_file(); getchar(); getchar(); return; } p p-next; } printf(未找到ID为%d的铠甲\n, armorId); printf(按任意键继续。。。\n); getchar(); getchar(); }4. 查看我的授权订单用户核心功能把订单和铠甲信息关联展示比单纯显示订单号更实用课设更容易拿高分void myOrders() { if (currentUser NULL) { printf(请先登录系统后再查看授权记录\n); getchar(); getchar(); return; } if (orderList NULL) { printf(系统暂无任何铠甲授权记录\n); getchar(); getchar(); return; } printf(\n你的铠甲授权记录\n); order* p orderList; int count 0; while (p ! NULL) { if (p-userId currentUser-id) { count; // 匹配订单对应的铠甲信息 movie* armor movieList; char armorType[20] 未知; char armorAttr[20] 未知; char armorStatus[20] 未知; while (armor ! NULL) { if (armor-id p-movieId) { strcpy(armorType, armor-type); if (armor-attr ATTR_FIRE) strcpy(armorAttr, 火属性); else if (armor-attr ATTR_WATER) strcpy(armorAttr, 水属性); else if (armor-attr ATTR_THUNDER) strcpy(armorAttr, 雷属性); else if (armor-attr ATTR_EARTH) strcpy(armorAttr, 土属性); else if (armor-attr ATTR_WIND) strcpy(armorAttr, 风属性); if (armor-status ARMOR_IDLE) strcpy(armorStatus, 闲置); else if (armor-status ARMOR_IN_BATTLE) strcpy(armorStatus, 战斗中); else if (armor-status ARMOR_REPAIRING) strcpy(armorStatus, 维修中); else if (armor-status ARMOR_DAMAGED) strcpy(armorStatus, 破损); break; } armor armor-next; } // 美化订单展示格式 printf(┌─────────────────────────────┐\n); printf(│ 授权单号: %d\n, p-id); printf(│ 铠甲名称: %s\n, p-movieName); printf(│ 铠甲类型: %s | 属性: %s\n, armorType, armorAttr); printf(│ 铠甲状态: %s\n, armorStatus); printf(│ 授权时长: %d 小时\n, p-quantity); printf(│ 总消耗: %.2f 元\n, p-totalPrice); if (p-monsterId 0) { printf(│ 战斗记录: 未讨伐任何怪兽\n); } else { printf(│ 战斗记录: 讨伐怪兽ID-%d%s\n, p-monsterId, p-battleResult 1 ? 胜利 : (p-battleResult 0 ? 失败 : 未完成)); } printf(└─────────────────────────────┘\n); } p p-next; } if (count 0) { printf(你暂无任何铠甲授权记录快去申请授权吧\n); } else { printf(\n共查询到 %d 条授权记录\n, count); } printf(\n按任意键继续。。。\n); getchar(); getchar(); }5. 初始化怪兽列表铠一 铠二经典怪兽增加趣味性void initMonsterList() { // 清空原有列表 monster* temp monsterList; while (temp ! NULL) { monster* next temp-next; free(temp); temp next; } monsterList NULL; const struct { int id; const char* name; int level; MonsterAttr attr; int danger; int isDefeated; } monsterdata[] { // 铠一经典怪兽 {101, 恶参兽, 1, ATTR_EARTH, 2, 1}, {102, 魔马兽, 2, ATTR_WIND, 4, 1}, {141, 穷奇, 8, ATTR_EARTH, 9, 1}, {142, 饕餮, 8, ATTR_FIRE, 9, 1}, {145, 黑魔兽, 10, ATTR_THUNDER, 10, 1}, // 铠二幽冥魔 {201, 路法, 10, ATTR_THUNDER, 10, 0}, {202, 安迷修, 9, ATTR_FIRE, 9, 0}, {203, 乔奢费, 9, ATTR_WIND, 9, 0}, {204, 库忿斯, 9, ATTR_EARTH, 9, 0} }; int monstercount sizeof(monsterdata) / sizeof(monsterdata[0]); for (int i 0; i monstercount; i) { monster* newmonster (monster*)malloc(sizeof(monster)); newmonster-id monsterdata[i].id; strcpy(newmonster-name, monsterdata[i].name); newmonster-level monsterdata[i].level; newmonster-attr monsterdata[i].attr; newmonster-danger monsterdata[i].danger; newmonster-isDefeated monsterdata[i].isDefeated; newmonster-next NULL; if (monsterList NULL) { monsterList newmonster; } else { monster* p monsterList; while (p-next ! NULL) p p-next; p-next newmonster; } } printf(怪兽列表初始化完成共加载 %d 只经典怪兽\n, monstercount); }三、课设踩坑总结纯纯血泪经验结构体复用比新建更重要一开始想新建armor结构体结果发现原有movie的链表、文件逻辑全要重写复用后只需要补字段节省 80% 时间枚举类型存文件要转数字直接存枚举会乱码转成 0/1/2... 存读出来再强转新手一定要注意空指针防护不能少未登录时currentUser是 NULL直接用currentUser-id必崩加个判断就能解决链表遍历要注意边界找最大 ID 时一定要遍历到nextNULL否则会漏数据用户体验细节加分比如订单展示用┌┐└┘美化、状态转文字、异常提示说清楚原因比光秃秃的文字更讨喜。四、扩展方向课设想拿高分可以加增加铠甲战斗功能根据铠甲属性和怪兽属性克制关系判断战斗结果增加管理员维修铠甲功能把破损铠甲改成维修中 / 闲置增加密码修改、用户注册功能增加怪兽封印记录讨伐成功后更新isDefeated字段。这套代码我已经跑通了把上面的函数补充到主函数菜单逻辑里就能直接用。主函数的菜单逻辑比较简单大家可以根据自己的课设要求写核心就是调用这些功能函数。最后说一句C 语言课设不用追求多复杂把基础的结构体、链表、文件操作做扎实再加点自己喜欢的个性化内容比如我加的铠甲勇士元素比纯写增删改查有意义多了也更容易记住知识点。