程序设计二次开发

项目二次开发

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

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

posted @ 2025-02-28 14:03  萱不败  阅读(43)  评论(0)    收藏  举报