【实训】“宅急送”订餐管理系统(程序设计综合能力实训)

简介: 【实训】“宅急送”订餐管理系统(程序设计综合能力实训)

前言

       大一小学期,我迎来了人生中的第一次实训,“宅急送”订餐管理系统是一个非常好的检验该阶段所学知识的实训项目,本篇文章我会围绕这一实训项目以及在实训中遇到的问题和收获与大家进行探讨,内容包括流程图、函数调用关系图、算法描述以及代码实现等等,可供大家进行参考,希望大家多多点赞收藏支持🔥

1.详细设计

1.1上班

1.1.1算法描述

首先对套餐顺序表进行初始化,然后从文件中读取套餐信息,并将其存储到套餐顺序表中,提示用户套餐信息读取完成,而后对订单信息队列进行初始化,从文件中读取订单信息,并将其存储到订单信息队列中,同样提示用户订单信息读取完成,最后则是对图进行初始化,从文件中分别读取地点信息和地点间距离信息,并将其存储到图中,提示地址和距离信息读取完成,而后等待用户进行下一步操作。


1.1.2流程图

1.2订单管理

1.2.1算法描述

1.接收订单

从用户输入获取订单信息,包括订餐人姓名、订单号和目的地等,并判断输入的订单信息是否合法,然后创建一个临时变量用来存储订单信息,最后将该临时变量入队。

2.根据订单号查询订单

从用户输入获取订餐人姓名,遍历队列中的每个节点,直到找到订单号匹配的节点为止,如果找到匹配的订单号,返回该节点的指针,否则返回空指针。

3.根据订餐人姓名查询订单

       从用户输入获取订餐人姓名,遍历队列中的每个节点,直到找到订餐人姓名匹配的节点为止,如果找到匹配的订餐人姓名,返回 true,否则返回 false。

4.根据订单号查询并修改订单

       调用订单号查询函数,获取该订单地址,根据用户输入的信息修改相应的订单属性,同样在其中穿插判断订单信息的合法性,最后更新订单信息。

5.根据订单号查询并取消订单

       从用户输入获取订单号,调用订单号查询函数,获取该订单地址,判断该订单是否已派送,将该订单状态信息更新为取消。

1.2.2流程图


1.3派送订单

1.3.1算法描述

1.遍历未派送订单

       以队列的size大小界定循环次数,遍历该队列,当派送状态为未派送时输出订单信息即可。

2.逐个派送

       首先找到订单队列中最靠近队首的未派送订单,然后利用弗洛伊德算法计算最短路径并生成最短距离矩阵D得到最短距离,和最短路径矩阵Path,利用PrintShortedPath函数输出最短路径,设骑手速度为30,计算出送达时间并输出,将订单状态修改为已派送,最后提示用户派送成功。

1.3.2流程图


1.4数据维护

1.4.1算法描述

1.添加套餐

 调用函数 CheckSetList检测套餐列表容量是否已满,如果已满则扩容,通过用户输入获取套餐信息,包括套餐编号、套餐名称、套餐描述、套餐价格和套餐状态,将获取的套餐信息依次存储到顺序表的末尾,增加顺序表长度,提示用户添加成功。

2.删除套餐

       通过用户输入获取要删除的套餐的编号,遍历顺序表中的每个套餐,直到找到与输入的编号匹配的套餐为止,如果找到匹配的套餐,询问用户是否确定删除该套餐,并根据用户的选择进行相应操作,如果用户确定删除套餐,则将该套餐从顺序表中删除,并提示用户删除成功。

3.根据套餐编号修改套餐信息

       通过用户输入获取要修改的套餐的编号,然后遍历顺序表中的每个套餐,直到找到与输入的编号匹配的套餐为止,如果找到匹配的套餐,通过用户输入修改套餐的名称、描述、价格和状态,提示用户修改成功,如果未找到匹配的套餐,提示用户修改失败并声明原因。

4.根据套餐名称修改套餐信息

   通过用户输入获取要修改的套餐的名称,然后遍历顺序表中的每个套餐,直到找到与输入的名称匹配的套餐为止,如果找到匹配的套餐,通过用户输入修改套餐的名称、描述、价格和状态,提示用户修改成功,如果未找到匹配的套餐,提示用户修改失败并声明原因。

5.恢复套餐信息

首先初始化顺序表,然后调用函数 LoadSetList加载文件中的套餐信息,并将其存储到顺序表中,提示用户恢复套餐成功,之后调用函数 TraverseSet 遍历并打印顺序表中的套餐信息。

1.4.2流程图


1.5统计

1.5.1算法描述

1.当天统计

   遍历订单队列,获取订单的时间信息,判断订单的时间是否为当天,如果是则进行统计,统计未派送数量、已派送数量、总套餐数和总金额,输出统计结果。

2.当月统计

       遍历订单队列,获取订单的时间信息,判断订单的月份是否为当月,如果是则进行统计,遍历套餐列表,匹配订单的套餐编号,统计未派送数量、已派送数量、套餐数和总金额,最终输出统计结果。

3.当周统计

       遍历订单队列,获取订单的时间信息,判断订单的日期是否在本周范围内,如果是则进行统计,遍历套餐列表,匹配订单的套餐编号,统计未派送数量、已派送数量、套餐数和总金额,最终输出统计结果。

4.按地址统计

       遍历订单队列,获取订单的地址信息,遍历地址数组,匹配订单的地址,遍历套餐列表,匹配订单的套餐编号,统计订单数量和总金额,最终输出统计结果。

1.5.2流程图

1.6下班

1.6.1算法描述

       将顺序表中的内容存储到文本文件中,然后销毁为顺序表开辟的动态内存空间,将队列中的内容存储到文本文件中,销毁为队列开辟的动态内存空间,提示用户信息储存完毕,等待用户退出程序。

1.6.2流程图


2.代码实现

=========================================================================

GITEE相关代码:🌟fanfei_c的仓库🌟

=========================================================================

3.函数调用关系

该图采用Mindmaster(亿图脑图)创作完成。


4.遇到的问题

1.fread与fwrite只能读取和写入二进制文件,不能读取文本文件(造成乱码的原因)

在实训初期,文件读取操作是比较棘手的难题,由于对于文件操作函数使用的不熟练,常常陷入读取文本出现乱码的问题,经过仔细研究文件操作函数,最终成功解决了这一问题。

为了以后方便学习,在套餐信息的读取和写入中我使用了二进制读取写入方式,而订单信息和图的信息我才用了文本读取写入方式。

二进制读取举例:

void Save_Set(SetList* s)//存储套餐信息文件
{
  FILE* pf = fopen("Menu_Info.txt", "w");//保存套餐信息到文件
  if (pf == NULL)
  {
    perror("fopen Menu_Info");
    return;
  }
  int i = 0;
  for (i = 0; i < s->length; i++)
  {
    fwrite(&s->setmea[i], sizeof(Meal), 1, pf);
  }
}
void LoadSetList(SetList* s)//加载套餐信息文件
{
  FILE* pf = fopen("Menu_Info.txt", "rb");
  if (pf == NULL)
  {
    perror("LoadSetList");
    return;
  }
  Meal tmp = { 0 };
  while (fread(&tmp, sizeof(Meal), 1, pf))
  {
    CheckSetList(s);
    s->setmea[s->length] = tmp;
    s->length++;
  }
  printf("Menu_Info.txt加载成功!\n");
  fclose(pf);
  return;
}

文本读取举例:

void Save_Book(Que* pq)// 存储订单信息文件
{
  FILE* pf = fopen("Book_Info.txt", "w");
  if (pf == NULL)
  {
    perror("fopen Book_Info");
    return;
  }
  while (!QueueEmpty(pq))
  {
    Order_Info tmp = { 0 };
    tmp = QueueFront(pq);
    fprintf(pf, "%s ", tmp.Order_Num);
    fprintf(pf, "%s ", tmp.Menu_Num);
    fprintf(pf, "%d ", tmp.Num);
    fprintf(pf, "%s ", tmp.Orderer_Name);
    fprintf(pf, "%s ", tmp.Order_Tele);
    fprintf(pf, "%s ", tmp.Address);
    fprintf(pf, "%s ", tmp.Order_Time);
    fprintf(pf, "%d ", tmp.Deliver_State);
    fprintf(pf, "%d\n", tmp.timestamp);
    QueuePop(pq);
  }
}
void LoadBook(Que* pq)//加载订单信息
{
  FILE* pf = fopen("Book_Info.txt", "r");
  if (pf == NULL)
  {
    perror("LoadBook");
    return;
  }
  char line[150];
  while (fgets(line, sizeof(line), pf)) // 逐行读取文件内容
  {
    Order_Info tmp = { 0 };
    sscanf(line, "%s %s %d %s %s %s %s %d %d", tmp.Order_Num, tmp.Menu_Num, &tmp.Num,
      tmp.Orderer_Name,tmp.Order_Tele,tmp.Address,tmp.Order_Time,&tmp.Deliver_State,&tmp.timestamp); // 解析行中的数据
    QueuePush(pq, tmp);
  }
  printf("Book_Info.txt加载成功!\n");
  fclose(pf);
  return;
}

大家如果对文件操作相关知识有所欠缺,可以浏览下我之前写的博客->【C语言】文件操作🍎

2.使用feof()函数判断文件结束是不合适的

       在处理文件指针时,判断文件是否已经到达末尾的一种常见方法是使用feof()函数(feof()函数会在文件指针到达文件末尾时返回非零值,否则返回0)

因此,在循环中使用while (!feof(pf))来判断文件是否到达末尾,看起来似乎是一种合理的做法。

       然而,实际上在循环中使用while (!feof(pf))可能会导致最后一次循环读取无效数据的问题。这是因为feof()函数的返回值只有在文件指针尝试读取文件末尾之后才会为真。也就是说,在feof()函数返回真之前,文件指针可能已经读取了文件末尾之后的数据,但循环仍然会继续执行一次。因此,在最后一次循环中,会读取到文件末尾之后的无效数据。

      为了避免这个问题,可以使用替代方案来处理文件指针。一种常见的替代方案是使用fgets()函数来逐行读取文件内容,并在循环中检查fgets()函数的返回值是否为NULL,以判断是否到达文件末尾。如果fgets()函数返回NULL,说明文件已经到达末尾,循环应该结束。这种方式可以确保最后一次循环不会读取无效数据。

使用fgets()函数逐行读取文件内容,当fgets()函数返回NULL时,循环结束。这样确保了最后一次循环不会读取无效数据。

while (fgets(line, sizeof(line), pf))
{
    // 处理每一行的数据
    // ...
}

   总结起来,建议避免在循环中使用feof()函数来判断文件是否到达末尾,而是使用替代方案如fgets()函数来处理文件指针,以确保最后一次循环不会读取无效数据。

下面是feof函数的正确使用方法:

int main()
{
  FILE* file = fopen("data.txt", "r");
  if (file == NULL)
  {
    perror("fopen");
    return 1;
  }
  char buffer[100];
  while (fgets(buffer, sizeof(buffer), file) != NULL)
  {
    printf("%s", buffer);
  }
  if (feof(file))//将feof的判断放在循环末尾
  {
    printf("Reached end of file.\n");
  }
  else
  {
    printf("Error occurred while reading file.\n");
  }
  fclose(file);
  return 0;
}

由于当fgets(buffer, sizeof(buffer), file)函数的返回值为NULL时,说明文件已经到达末尾,此时循环结束,再利用feof(file)做判断,如果此时feof(file)的返回值为真,证明文件确实到达了末尾,但如果feof(file)的返回值为假,那证明文件在读取的过程中发生了错误,需要进行检查。

由此才是feof()函数的正确用法,这样的方法也更加严谨安全

3.跨文件结构体指针作为参数无法识别,必须使用struct +结构体名

这个问题是在基本完成各个源文件后,合并在一起实现时出现的问题,即多文件形式引起的错误,我发现虽然在头文件中定义结构体:

typedef struct Queue
{
}Queue;

在函数形参中,参数格式为Queue* 即可,但我发现编译器会报错,当加上struct Queue*就不报错了,所以我推测跨文件结构体指针作为参数无法识别,必须适用struct Queue*的格式才行,下面是问题截图:


   当然,这只是我的推测,在请教学校老师后,老师给了我这个答案:可能是我所使用的编译器不支持省略struct的写法,如果有大佬发现我的说法是错误的话,希望可以帮我指正出来,谢谢!

4.统计板块中的时间识别问题

如何界定统计中的当日统计、当月统计和本周统计呢,我的思路是将订单结构体中新增一个结构体变量time_t timestamp,在日后需要识别订单时间时,利用localtime(&p->data.timestamp),就能拿到订单的时间了,否则还需要对时间字符串char Order_Time[25]进行转化识别,下面是localtime返回值tm结构体的成员,可作为参考:


诚然这种思路可以实现统计的功能,但在本周统计上,仍然需要考虑该周跨月甚至跨年的问题,我感觉较为繁琐,不知道大家对于统计的算法有没有什么更好的思路可以分享的呢,欢迎大家在评论区多多交流🌝

5.需要读取的时间字符串中间存在空格

订单信息中的下单时间,需求文档中给定的格式是2023-08-28 19:00:00,日期和时间中间存在一个空格,这就与其他信息间存在冲突,因为读取文件信息我采用的是sscanf函数,sscanf遇到空格即停止读取,这也是一段字符串中不同内容可以区分的特性,而时间字符串中存在一个空格,这就导致sscanf读取到2023-08-28即停止,19:00:00就被认为是下一个内容了。

 我的解决方案是将时间的格式更改为2023-08-28/19:00:00,这样就解决了这一问题。


 但其实这是一种妥协,另一种方法则是将日期2023-08-29看作一个字符串,将时间14:53:30看作一个字符串,分别读取到不同的结构体变量中,当然如果大家有更好的方法,希望可以分享在评论区😁


总结

 本次实训极大的考验了我的代码能力,在程序设计前期,由于对文件操作知识掌握相对薄弱,对于二进制读取和文本读取还没有清晰的认识,导致在测试调试过程中常常出现乱码等问题,甚至在实训前期一度对自己产生怀疑,但好在翻过了文件操作这一座高山,其他的问题基本上就是轻舟已过万重山。

为期两周的实训结束了,我交上了自己还算满意的答卷,大一小学期的这次实训让我收获满满,也希望各位读者在文章中我遇到的问题上可以给出指导或建议,谢谢大家!

目录
打赏
0
0
0
0
1
分享
相关文章
如何运用C#.NET技术快速开发一套掌上医院系统?
本方案基于C#.NET技术快速构建掌上医院系统,结合模块化开发理念与医院信息化需求。核心功能涵盖用户端的预约挂号、在线问诊、报告查询等,以及管理端的排班管理和数据统计。采用.NET Core Web API与uni-app实现前后端分离,支持跨平台小程序开发。数据库选用SQL Server 2012,并通过读写分离与索引优化提升性能。部署方案包括Windows Server与负载均衡设计,确保高可用性。同时针对API差异、数据库老化及高并发等问题制定应对措施,保障系统稳定运行。推荐使用Postman、Redgate等工具辅助开发,提升效率与质量。
2025 蛇年,J 人直播带货教育科普团队的 6 款高效协作软件。
2025年蛇年新春,直播带货行业将迎来流量高峰。视频剪辑团队在这一购物狂欢中扮演关键角色,其工作效率直接影响直播间人气与销量。为提升协作效率,J人主导的公司选择合适的可视化办公软件至关重要。板栗看板、Trello、Asana、Miro、Monday.com和Wrike等工具从不同维度助力视频剪辑团队,实现创意与效率的完美结合。这些软件分别在流程可视化、任务管理、跨部门协同、创意激发、数据驱动及权限管控等方面提供强大支持,确保公司在激烈竞争中脱颖而出,收获流量与销量双丰收。
99 25
2024年十大工程管理软件评测:哪些任务可视化工具能显著提高团队效率?
在数字时代,团队协作和项目管理的效率至关重要。任务可视化工具通过直观展示任务进展、资源分配和优先级,帮助团队高效协作,减少误解和沟通成本。这类工具如Trello、Asana、ClickUp等,不仅提升了任务透明度和团队协作效率,还支持实时监控与反馈,特别适合远程工作和跨部门协作。
2024年十大工程管理软件评测:哪些任务可视化工具能显著提高团队效率?
寻找设计行业项目可视化办公软件,怎么这么难!你有招吗?
本文介绍了6款适用于设计行业的可视化办公管理软件,包括板栗看板及5款国外知名软件,如Trello、Asana、Monday.com和Basecamp。各软件在团队协作、任务管理、文件共享等方面各有特色,适合不同类型的设计团队使用。板栗看板本地化适配强,Trello灵活定制,Asana功能全面,Monday.com个性化定制突出,Basecamp注重简洁易用。文章旨在帮助设计团队根据自身需求选择最适合的软件,提升项目管理效率。
78 13
程序员中医诊所管理软件开发模块分析
将系统划分为患者管理模块、医生管理模块、药材药方管理模块、财务管理模块、报表统计模块和系统设置模块。
85 2
问卷调查软件精选,效能与易用双赢
本文推荐了四款问卷调查软件:ZohoSurvey、SurveyMonkey、GoogleForms和Typeform。ZohoSurvey功能全面,性价比高,适合中小企业和个人;SurveyMonkey功能强大,适合大型企业和科研机构;GoogleForms免费易用,适合预算有限的用户;Typeform注重用户体验,适合需要高参与率的调查。选择时需综合考虑功能、易用性和品牌信任度等因素。
125 2
无代码平台也能实现园区物业管理系统 让普通人成为开发者 常见的软件盘点
- **草料二维码**:适用于中小物业,提供设备至访客管理的多种场景,免费但无财务催收功能。 - **优房物业管理系统**:专注物业费收缴,有员工工作台,适合需高效催缴的物业。 - **诺怀云物业**:全场景云系统,适合大型机构如商业资产和医院后勤,提供一体化解决方案。 - **OPark智慧园区**:全面的园区管理平台,强调招商与运营管理,适合预算充足且需定制服务的园区运营者。 - **明源云数智**:侧重招商与渠道管理,自动化任务执行,适合大型园区的财务管理和服务优化。
B/S架构,采用JAVA编程的医院云HIS系统源码,公立二甲医院应用案例
SaaS模式Java版云HIS系统,在公立二甲医院应用多年,经过多年持续优化系统运行稳定、功能齐全,界面布局合理、操作简便。融合B/S版电子病历系统,支持电子病历四级,HIS与电子病历系统均拥有自主知识产权。 云HIS系统采用云端SaaS服务的方式提供,使用用户通过浏览器即能访问,无需关注系统的部署、维护、升级等问题,系统充分考虑了模板化、配置化、智能化、扩展化等设计方法,覆盖了基层医疗机构的主要工作流程,能够与监管系统有序对接,并能满足未来系统扩展的需要。
114 0
B/S架构,采用JAVA编程的医院云HIS系统源码,公立二甲医院应用案例
智慧校园管理平台源码(含教师端、家长端、学生端小程序)
智慧校园以互联网为基础,“大数据+云服务+云计算”为核心,融合校园教学、管理、生活软硬件平台,定义智慧校园新生活。智慧校园管理平台管理者、教师、学生、家长提供一站式智慧校园解决方案,实现校园管理智能、.校园生活一体化、校园设施数字化、课堂教学生动化、家校沟通无缝化。集成智能硬件及第三方服务,面向学校、教师、家长、学生,将校内外管理、教学等信息资源进行整合,利用微信端的交互系统实现家校互联。
413 1
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等