建立网站功能,wordpress机器爬虫爬资讯,文创产品设计公司,安徽省建设工程信息网网#x1f440;樊梓慕#xff1a;个人主页 #x1f3a5;个人专栏#xff1a;《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》
#x1f31d;每一个不曾起舞的日子#xff0c;都是对生命的辜负 前言 大一小学期#xff0c;我迎来了人生中的第一次实训…
樊梓慕个人主页 个人专栏《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》
每一个不曾起舞的日子都是对生命的辜负 前言 大一小学期我迎来了人生中的第一次实训“宅急送”订餐管理系统是一个非常好的检验该阶段所学知识的实训项目本篇文章我会围绕这一实训项目以及在实训中遇到的问题和收获与大家进行探讨内容包括流程图、函数调用关系图、算法描述以及代码实现等等可供大家进行参考希望大家多多点赞收藏支持 欢迎大家收藏以便未来做题时可以快速找到思路巧妙的方法可以事半功倍。 GITEE相关代码fanfei_c的仓库 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看作一个字符串分别读取到不同的结构体变量中当然如果大家有更好的方法希望可以分享在评论区 总结 本次实训极大的考验了我的代码能力在程序设计前期由于对文件操作知识掌握相对薄弱对于二进制读取和文本读取还没有清晰的认识导致在测试调试过程中常常出现乱码等问题甚至在实训前期一度对自己产生怀疑但好在翻过了文件操作这一座高山其他的问题基本上就是轻舟已过万重山。 为期两周的实训结束了我交上了自己还算满意的答卷大一小学期的这次实训让我收获满满也希望各位读者在文章中我遇到的问题上可以给出指导或建议谢谢大家 如果你对该系列文章有兴趣的话欢迎持续关注博主动态博主会持续输出优质内容
博主很需要大家的支持你的支持是我创作的不竭动力
~ 点赞收藏关注 ~