程序设计二次开发

news/2025/2/28 14:07:34/文章来源:https://www.cnblogs.com/xuanyk/p/18743124

项目二次开发

2352509 康雅萱 软工一班

来源:同学(2352503 王以纯)的程序设计期末大作业报告--餐厅信息管理程序

一、餐厅信息管理程序
运行环境:Dev C++
基本要求:
1.要求实现客户点菜的过程、客户结账、账目的管理、餐厅系统的维护四大功能模块,每个功能模块又分别对应一些不同操作子模块,从而完成一个餐厅信息管理信息系统。
2.可以使用三种不同的结构体来分别存储餐桌、菜以及订单信息。
3.使用链表来实现创建客户订单与客户结账等操作。
4.使用文本文件完成数据的存储与读取,完成账单的管理。
5.系统制作完成后应实现类似下图所示界面。

二、完整可编辑且加有适当注释的源代码

点击查看代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>// 客户订单结构体
typedef struct Order {int orderNumber;char dish[50];float price;struct Order* next;
} Order;struct table{int table_num;int seat;int occupied;
}tables[10];struct dish{int dishnum;char dishname[20];int price;struct dish* next;
}dishes[10];// 创建新的订单节点
Order* createOrder(int orderNumber, const char* dish, float price) {Order* newOrder = (Order*)malloc(sizeof(Order));newOrder->orderNumber = orderNumber;strcpy(newOrder->dish, dish);newOrder->price = price;newOrder->next = NULL;return newOrder;
}// 添加订单到链表
void addOrder(Order** head, Order* newOrder) {if (*head == NULL) {*head = newOrder;} else {Order* current = *head;while (current->next != NULL) {current = current->next;}current->next = newOrder;}
}// 打印订单信息
void printOrder(Order* order) {printf("订单编号: %d, 菜品: %s, 价格: %.2f\n", order->orderNumber, order->dish, order->price);
}// 保存订单到文件
void saveOrdersToFile(Order* head) {FILE* file = fopen("orders.txt", "w");if (file == NULL) {printf("无法打开文件!\n");return;}Order* current = head;while (current != NULL) {fprintf(file, "%d %s %.2f\n", current->orderNumber, current->dish, current->price);current = current->next;}fclose(file);printf("订单已保存到文件!\n");
}// 从文件加载订单
Order* loadOrdersFromFile() {Order* head = NULL;FILE* file = fopen("orders.txt", "r");if (file == NULL) {printf("无法打开文件!\n");return head;}int orderNumber;char dish[50];float price;while (!feof(file)) {fscanf(file, "%d %s %f\n", &orderNumber, dish, &price);Order* newOrder = createOrder(orderNumber, dish, price);addOrder(&head, newOrder);}fclose(file);printf("订单已从文件加载!\n");return head;
}// 释放订单链表内存
void freeOrders(Order* head) {Order* current = head;while (current != NULL) {Order* temp = current;current = current->next;free(temp);}
}int main() {Order* head = NULL;int orderNumber=1,i,choice,j,prices;struct dish dishes[10]={{1,"宫爆鸡丁",30},{2,"麻辣香锅",40},{3,"水煮鱼",50},{4,"小炒肉",25},{5,"炒青菜",15},{6,"番茄炒蛋",15},{7,"醋溜土豆丝",15},{8,"紫菜蛋花汤",20},{9,"小酥肉",15},{10,"蛋炒饭",25}};struct dish* p,*head1,*c;head1=dishes;p=head1;do {printf("==========================\n");printf("餐厅服务系统\n");printf("==========================\n");printf("1. 点菜\n");printf("2. 客户结账\n");printf("3. 账目管理\n");printf("4. 餐馆统计\n");printf("5. 退出\n");printf("请输入您的选择:");scanf("%d", &choice);switch (choice) {case 1: {printf("菜单为:\n");for(i=1;i<=10;i++){if(i<10) p->next=dishes+i;else p->next=NULL; printf("%d %s %d\n",p->dishnum,p->dishname,p->price);if(i<10) p=p->next;}int num;printf("请输入点菜数量:");scanf("%d",&num);Order* newOrder=NULL;for (i=0;i<num;i++) {int dishn;char dish[50];printf("请输入第%d个菜品序号:",i+1);scanf("%d",&dishn);p=head1;while(p!=NULL){for(j=0;j<10;j++){if(p->dishnum==dishn){prices=p->price;strcpy(dish,dishes[j].dishname);break;}else {c=p;p=p->next;}} if(j!=10) break;}p=head1;if (newOrder==NULL) {newOrder=createOrder (orderNumber,dish,prices);addOrder (&head,newOrder);} else {Order* additionalOrder=createOrder (orderNumber,dish,prices);addOrder (&(newOrder->next),additionalOrder);}orderNumber++;}printf("点菜成功!\n");break;}case 2: {if (head == NULL) {printf("当前没有订单!\n");} else {printf("订单列表:\n");Order* current = head;while (current != NULL) {printOrder(current);current = current->next;}printf("请选择结账订单编号:");int checkoutOrderNumber;scanf("%d", &checkoutOrderNumber);current = head;Order* previous = NULL;while (current != NULL) {if (current->orderNumber == checkoutOrderNumber) {if (previous != NULL) {previous->next = current->next;} else {head = current->next;}printOrder(current);free(current);break;}previous = current;current = current->next;}}break;}case 3: {if (head == NULL) {printf("当前没有订单!\n");} else {Order* current = head;while (current != NULL) {printOrder(current);current = current->next;}}break;}case 4: {saveOrdersToFile(head);break;}case 5:break;default:printf("无效的选择!\n");break;}} while (choice != 5);freeOrders(head);return 0;
}
三、代码问题及修正

(1) 点菜功能中的逻辑问题
在点菜功能中,newOrder 的使用逻辑存在问题。newOrder 被错误地用作链表的中间节点,而实际上应该直接将新订单添加到链表中。
修正代码:
case 1: {
printf("菜单为:\n");
for (i = 0; i < 10; i++) {
printf("%d %s %d\n", dishes[i].dishnum, dishes[i].dishname, dishes[i].price);
}

int num;
printf("请输入点菜数量:");
scanf("%d", &num);

for (i = 0; i < num; i++) {
int dishn;
printf("请输入第%d个菜品序号:", i + 1);
scanf("%d", &dishn);

int found = 0;
for (j = 0; j < 10; j++) {if (dishes[j].dishnum == dishn) {Order* newOrder = createOrder(orderNumber, dishes[j].dishname, dishes[j].price);addOrder(&head, newOrder);orderNumber++;found = 1;break;}
}
if (!found) {printf("未找到菜品编号:%d,请重新输入!\n", dishn);i--; // 重新输入当前菜品
}

}
printf("点菜成功!\n");
break;}

修正点:
修复了点菜逻辑,直接将新订单添加到链表中。
增加了菜品编号验证,如果输入的编号无效,提示用户重新输入

(2)文件加载订单时的逻辑问题
在 loadOrdersFromFile 函数中,while (!feof(file)) 的使用方式可能导致重复读取最后一行数据。
修正代码:
Order* loadOrdersFromFile() {
Order* head = NULL;
FILE* file = fopen("orders.txt", "r");
if (file == NULL) {
printf("无法打开文件!\n");
return head;
}

int orderNumber;
char dish[50];
float price;

while (fscanf(file, "%d %s %f", &orderNumber, dish, &price) == 3) {
Order* newOrder = createOrder(orderNumber, dish, price);
addOrder(&head, newOrder);
}

fclose(file);
printf("订单已从文件加载!\n");
return head;}

修正点:
使用 fscanf 的返回值判断是否成功读取一行数据,避免 feof 的误用。

三、优化实现

1.动态菜单管理

菜单结构体和链表操作:

typedef struct Dish {
int dishnum;
char dishname[20];
float price;
struct Dish* next;} Dish;

Dish* createDish(int dishnum, const char* dishname, float price) {
Dish* newDish = (Dish)malloc(sizeof(Dish));
newDish->dishnum = dishnum;
strcpy(newDish->dishname, dishname);
newDish->price = price;
newDish->next = NULL;
return newDish;}
void addDish(Dish** head, Dish newDish) {
if (head == NULL) {
head = newDish;
} else {
Dish current = head;
while (current->next != NULL) {
current = current->next;
}
current->next = newDish;
}}
void printDishes(Dish head) {
if (head == NULL) {
printf("菜单为空!\n");
return;
}
Dish current = head;
while (current != NULL) {
printf("%d %s %.2f\n", current->dishnum, current->dishname, current->price);
current = current->next;
}}

动态菜单初始化:
Dish* headDish = NULL;addDish(&headDish, createDish(1, "宫保鸡丁", 30));addDish(&headDish, createDish(2, "麻辣香锅", 40));addDish(&headDish, createDish(3, "水煮鱼", 50));// 其他菜品...

订单统计功能
统计销售额和点菜次数最多的菜品:
void printOrderStatistics(Order* head) {
if (head == NULL) {
printf("当前没有订单!\n");
return;
}

float totalSales = 0;
int maxCount = 0;
char mostOrderedDish[50] = "";
int dishCount[100] = {0}; // 假设菜品编号不超过100

Order* current = head;
while (current != NULL) {
totalSales += current->price;
dishCount[current->orderNumber]++;
if (dishCount[current->orderNumber] > maxCount) {
maxCount = dishCount[current->orderNumber];
strcpy(mostOrderedDish, current->dish);
}
current = current->next;
}

printf("总销售额:%.2f元\n", totalSales);
printf("点菜次数最多的菜品:%s,共点%d次\n", mostOrderedDish, maxCount);}
持久化存储优化
优化文件格式和错误处理:
void saveOrdersToFile(Order* head) {
FILE* file = fopen("orders.txt", "w");
if (file == NULL) {
printf("无法打开文件!\n");
return;
}

Order* current = head;
while (current != NULL) {
fprintf(file, "%d %s %.2f\n", current->orderNumber, current->dish, current->price);
current = current->next;
}

fclose(file);
printf("订单已成功保存到文件!\n");}
Order* loadOrdersFromFile() {
Order* head = NULL;
FILE* file = fopen("orders.txt", "r");
if (file == NULL) {
printf("无法打开文件!\n");
return head;
}

int orderNumber;
char dish[50];
float price;

while (fscanf(file, "%d %s %f", &orderNumber, dish, &price) == 3) {
Order* newOrder = createOrder(orderNumber, dish, price);
addOrder(&head, newOrder);
}

fclose(file);
printf("订单已成功从文件加载!\n");
return head;}
四、测试截图

五、总结与思考

1.难点与耗时点总结

(1) 动态数据结构的实现
-难点:将静态的菜单和订单管理改为动态链表结构,需要重新设计数据的存储和访问方式。这不仅涉及到链表的基本操作(如插入、删除、查找),还需要确保内存管理正确,避免内存泄漏。
-耗时点:动态菜单的实现需要对链表操作非常熟悉,尤其是在添加、删除菜品时,链表的连接关系容易出错。此外,动态菜单的初始化和遍历也需要仔细设计,以确保功能的正确性。
-解决方法:通过逐步调试和单元测试,确保每个链表操作的正确性。同时,将链表操作封装为独立函数,减少重复代码,降低出错概率。

(2) 功能模块化与复用

难点:将重复的逻辑抽象为通用函数时,需要考虑函数的通用性和扩展性。例如,订单统计功能需要同时处理销售额和点菜次数统计,如何设计一个灵活的统计框架是一个挑战。
耗时点:模块化设计需要对代码逻辑有清晰的理解,同时要确保模块之间的接口设计合理。在实现过程中,频繁的重构和测试花费了较多时间。
解决方法:通过编写伪代码和流程图,提前规划模块的功能和接口。在实现过程中,逐步验证每个模块的正确性,并通过单元测试确保模块之间的协作无误。
逆向软件工程的思考
(1) 逆向工程的意义
逆向工程不仅是对现有代码的分析和理解,更是对软件设计思路的重新审视。通过逆向分析,可以发现原代码中的设计缺陷、冗余逻辑和潜在问题,从而为优化和重构提供依据。

(2) 逆向工程的实践方法

代码分析:通过阅读代码、绘制流程图和结构图,理解代码的逻辑和功能。重点关注代码的模块划分、数据结构设计和关键算法。
功能测试:在优化过程中,保持原有功能不变是关键。通过编写测试用例,验证每个功能模块的正确性,确保优化后的代码与原代码功能一致。
逐步重构:逆向工程不是简单的重写,而是逐步优化。在重构过程中,先保留原代码的核心逻辑,逐步引入新的设计和功能,避免一次性大改导致的不可控风险。
(3) 逆向工程的挑战

代码质量差异:原代码的质量直接影响逆向工程的难度。如果原代码缺乏注释、结构混乱或存在大量冗余逻辑,逆向分析将变得非常困难。
需求变更:在逆向工程过程中,需求可能会发生变化。如何在满足新需求的同时,保持代码的可维护性和扩展性是一个挑战。
性能与功能的平衡:优化代码时,需要在性能和功能之间找到平衡。过度优化可能导致代码复杂度增加,而忽略性能优化又可能影响用户体验。
总结与反思
通过这次优化实践,我深刻体会到逆向工程的重要性。它不仅帮助我理解了原代码的设计思路,还让我学会了如何在现有基础上进行优化和扩展。以下是我的几点总结:

(1) 深入理解代码是优化的基础
在优化代码之前,必须深入理解其逻辑和结构。逆向工程是实现这一目标的有效方法,通过逐步分析和重构,可以逐步优化代码。

(2) 模块化设计的重要性
模块化设计不仅提高了代码的可读性和可维护性,还为未来的功能扩展提供了便利。在优化过程中,将重复逻辑封装为独立模块,可以减少冗余代码,降低出错概率。

(3) 优化是一个逐步的过程
优化代码时,不能一蹴而就。需要逐步重构,保持原有功能不变,同时逐步引入新的设计和功能。通过单元测试和功能测试,确保每次优化的正确性。

(4) 逆向工程的局限性
逆向工程虽然强大,但也存在局限性。如果原代码质量较差,逆向分析可能会非常困难。此外,需求变更可能导致逆向工程的方向发生变化,需要灵活调整优化策略。

通过这次实践,我不仅提升了代码优化能力,还对逆向工程有了更深刻的理解。这些经验将为我未来的工作和学习提供宝贵的参考。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/891151.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Windows 系统调用学习笔记

依然是 x86 的,照着 lzyddf 师傅的 blog 和 OneTrainee师傅的blog 学的 Windows API Application Programming Interface,简称 API 函数。Windows API 是微软为 Windows 操作系统提供的一组函数、数据结构、常量和协议,允许开发者与操作系统进行交互。通过 Windows API,开发…

作业一:自我介绍+软工五问

作业一这个作业属于哪个课程 https://edu.cnblogs.com/campus/gdgy/SoftwareEngineeringClassof2023这个作业要求在哪里 https://edu.cnblogs.com/campus/gdgy/SoftwareEngineeringClassof2023/homework/13325这个作业的目标 学习使用github和博客园自我介绍、兴趣爱好 我叫梁鑫…

deepseek---官方API接入

最近deepseek又开放充值了,而且还大降价,果断接入: 1、首先就是去充值,然后获取key 2、打开接口文档-找到合适自己的语言接口 3、直接复制代码就能运行<?php$curl = curl_init();curl_setopt_array($curl, array(CURLOPT_URL => https://api.deepseek.com/chat/comp…

香港服务器选择指南:高防 vs 站群 vs GPU场景解析

一、引言 背景:香港作为亚太地区数据中心枢纽,凭借国际带宽、网络自由、法律完善等优势,成为企业全球化布局的首选节点。 目标:解析香港服务器在不同业务场景下的选择逻辑,帮助企业根据需求匹配高防、站群或GPU服务器。 二、香港服务器的核心优势 | 网络自由性:| 国际带…

大模型常见文件格式safetensors vs. gguf

safetensorsHeader: 文件的元数据(大小、版本) Meta data: 列表,每个元素表示文件里存的张量的类型、形状、偏移量 Tensor data: 列表元素对应的张量数据ggufgguf不依赖外部的配置文件,它可以把配置文件、词表、tokenizer、template等存入gguf中(如果一个模型有多个gguf文…

2025年最值得入手的CRM系统!这5款真的好用不踩坑

挑CRM真让人头大!有的太复杂,上手难 有的功能太少,啥都干不了 有的收费离谱,小团队根本用不起别担心!今天就给大家盘点5款2025年最值得入手的CRM系统,每一款都是真实用户口碑不错的,不管你是创业小团队,还是大公司,这里面肯定有一款适合你。 ​​ 一、简道云CRM 如果你…

web开发 辅助学习管理系统开发日记 day4

/**法法法!!!忘记保存发布了,写了一天的草稿直接没了,我晕死,今天补档昨天的吧。 */今天开始开发员工管理模块了,也得知了3月14有校招的消息,看来要加快进度了(╯▔皿▔)╯ Q1:今天调了一个时间最长的bug,在写分页查询的时候我将三层架构全部写完之后,运行程序下面报…

Web前端入门第3问:前端需要学习哪些技术?

Web前端开发技术学习路径基础知识必备 HTML+CSS+JavaScript ,就目前来看,这三板斧是入门前端开发的门槛,无论如何都是逃不掉了。进阶知识必须会一门主流的前端框架,比如:React/Vue/Angular/Svelte,就国内的从业环境来看,Vue占有绝对优势,后续也会写一些 vue 相关的文章…

Web前端入门第1问:英语是否很重要?有哪些前置条件?

HELLO,这里是大熊学习前端开发的入门笔记。 本系列笔记基于 windows 系统。 在入门之前,是否有这样的疑问: 程序员的英语是否很牛?毕竟程序员的代码像天书一样,比如这样:答案是否定的。 英语并不是编程的前置条件,不要被看似天书的代码吓到,程序代码都存在一定的语法结…

红外成像工具 非接触式热成像仪 高精度温度测量与多功能应用

红外成像工具 非接触式热成像仪 高精度温度测量与多功能应用IFD-x是一款非接触式热成像仪器,采用红外阵列高精度温度传感器和先进的软件算法。该设备能够对视场范围内的物体进行红外成像,成像分辨率达到512*384像素,温度灵敏度为0.1℃,绝对精度为1.5℃,刷新频率最高可达64…

Educational Codeforces Round 175 (Rated for Div. 2) 比赛记录

Educational Codeforces Round 175 (Rated for Div. 2) 比赛记录 比赛连接 手速场,上蓝场,但是有点唐,C 想错了写了半个多小时,想到正解不到 \(10\) 分钟就写出来了,看到 D 后悔没先做 D 了,过于简单了。 赛时切掉了 A - D,也算是成功渡劫上蓝了! 过题记录:A. FizzBuzz…

numpy知识点

1.点乘 .dot() 2.转置 .T 3.求逆矩阵np.linalg.inv() 4.拼接(返回变化后,但是并不对原来对象更改) np.concatenate((要拼接的ndarray对象),axis=按哪个维度拼接) axis=0 -->行增加 axis=1-->列增加 对于如果只有一个维度的ndarray,那么只能增加列,一直只有一行import…