一、课题内容和要求
1、问题描述
编写一份简化的食堂自动化管理系统,实现学生就餐卡管理和菜品管理以及消费记录统计等相关功能。所有数据包括学生就餐卡信息,菜品信息等都要利用文件系统保存,以备系统下次运行时使用。通过此课题,熟练掌握文件、数组、指针的各种操作,以及一些基本算法的应用。
2、功能要求
(1)学生就餐卡和菜品数据是由多条数据记录构成,其信息包括:
学生就餐卡:卡号,姓名,余额,状态(正常和挂失。)
食堂菜品数据:编号 名称 金额 消费次数
(2)数据保存形式:
所有就餐卡信息,菜品信息数据要以文本或二进制文件保存。
(3)需要实现的功能
代码要能提供以下两个基本模块。
管理员模块:
管理员以密码登录系统,可以完成以下功能
A. 注册学生就餐卡
B.就餐卡的充值挂失模块
C.食堂菜单管理功能,包括对菜单的增删修改查等功能。
学生模块:
以就餐卡号登录系统(说明:卡处于挂失,则拒绝登录。)
可以查询卡中余额。
可以查询本卡的消费记录(选做)
可以浏览菜品并按照金额购买
(4)界面功能要求:
A.采用友好的字符界面,实现一个功能控制菜单。
B.每次操作都从该菜单选择,利用循环结构使得一次运行程序可进行多次操作。
选做要求:
(1)数据完整性保证。例如:就餐卡号和菜单编号不得重复。
(2)学生每次消费可以自动生成消费记录(卡号,购买时间,购买菜品编号,购买金额)。该消费记录表永久保存,用于事后查询和统计。具体请学生自己构思、设计。
二、需求分析
食堂自动化管理系统的功能框架图如图所示。
(1) 提供可操作的主菜单:输出菜单,用于显示以从文件中加载的主菜单信息和若干个可选的功能选项。根据客户输入的选项来进入不同的模式,运行不同的函数。流程操作如下图所示。
(2)程序入口与多级菜单显示:在主菜单下,根据用户输入的不同选择,进入各级菜单,进而调用不同的函数,实现不同的功能。
(3)数据结构体的设计与初始化:在程序一开始就将自动构建各类用户结构体的实例,并且构造实例,为不同用户提供服务。在用户进行不同的选择时,会读入不同的数据信息,来构建具体的结构体实例,以满足用户需求。
(4)用户信息存储:在程序一始,会将相关数据结构自动初始化置空。在用户使用非存储类功能时,将不会对相关数据信息进行任何更改,也不涉及对文件内容的读写操作;当用户使用设计相关信息存储的功能时,将会从文件中按需写入相关信息到结构体中,在使用完毕后,再次进行信息的存储。如果是仅涉及存储,不涉及更改已存入信息功能的函数,将限制其使用文件的权限,已达到相关数据安全的保障。
(5)面向不同用户的功能协调:本程序设计了两种不同的用户模式:管理员模式与学生模式;程序的主入口是一致的,都将由用户来选择进入任何一种模式继续运行,两种模式都是采用一定的检测手段来进行登录使用,如下图所示。
三、概要设计
主要存储结构
// 代码很烂,轻喷。注:仅供参考学习使用。
//主要存储结构
//================ 结构体 ================
struct Student{
char card_num[20]; //卡号
char name[20];//姓名
char money[20];//余额
char mode[2];//状态
};
typedef struct Student student;//别名student
struct Food{
char id[20];
char name[20];
char price[20];
char num[10];
};
typedef struct Food food;//和student内容相似
struct Record{
char stu_id[20];
char food_id[20];
char food_price[20];
char record_time[255];
};
typedef struct Record record;//和student内容相似
四、源程序代码
// 代码很烂,轻喷。注:仅供参考学习使用。
//头文件
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
//全局变量定义
#define USER_FILE "user.txt"
#define RECORD_FILE "record.txt"
#define FOOD_FILE "food.txt"
#define CONSOLE "CON"
#define BUFLEN 255
#define NUM 50
#define password 123
//================ 结构体 ================
struct Student{
char card_num[20]; //卡号
char name[20];//姓名
char money[20];//余额
char mode[2];//状态
};
typedef struct Student student;//别名student
struct Food{
char id[20];
char name[20];
char price[20];
char num[10];
};
typedef struct Food food;//和student内容相似
struct Record{
char stu_id[20];
char food_id[20];
char food_price[20];
char record_time[255];
};
typedef struct Record record;//和student内容相似
//================ 函数声明 ================
//主函数
int main(void);
//重启函数
void rerun();
//主菜单显示
int menu();
//结构体内容初始化
void init(student *stu,food *fd,record *re);
//从文件读入学生卡信息
void readfile(student *stu);
//从文件读入菜品信息
void readfood(food *fd);
//从文件读入记录信息
void readrecord(record *re);
//保存学生信息
void savefile(student *stu);
//保存食物信息
void savefood(food *fd);
//保存记录信息
void saverecord(record *re);
//管理模式
void admin_mode(student *stu,food *fd);
//管理模式菜单
int admin_menu();
//注册学生卡
void regist();
//充值
void charge(student *stu);
//挂失
void report_of_loss(student *stu);
//解挂
void hanging_solutions(student *stu);
//注销
void del(student *stu);
//录入菜品
void input(food *fd);
//查询菜品
void check(food *fd);
//统计功能 (打印所有菜品信息)
void count(food *fd);
//学生模式
void stu_mode(student *stu,food *fd,record *re);
//学生模式菜单
int stu_menu();
//查余额
void surplus(student *stu,char *num);
//消费记录
void sturecord(record *re,char *num);
//购物
void purchase(student *stu,food *fd,char *num);
//================ 程序辅助功能实现 ================
//结构体内容初始化
void init(student *stu,food *fd,record *re){
for(int i = 0; i<NUM;i++){
strcpy(stu[i].card_num,"");
strcpy(stu[i].name,"");
strcpy(stu[i].money,"");
strcpy(stu[i].mode,"");
}
for(int i = 0; i<NUM;i++){
strcpy(fd[i].id,"");
strcpy(fd[i].name,"");
strcpy(fd[i].price,"");
strcpy(fd[i].num,"");
}
for(int i = 0; i<BUFLEN;i++){
strcpy(re[i].stu_id,"");
strcpy(re[i].food_id,"");
strcpy(re[i].food_price,"");
strcpy(re[i].record_time,"");
}
}
//从文件读入学生卡信息
void readfile(student *stu){
int i=0;
//输入重定向,从文件输入。
freopen(USER_FILE, "r", stdin);
for(i=0;i<NUM;i++){
// while(~scanf("%s%s%s%s", stu[i].card_num,stu[i].name, stu[i].money,stu[i].mode));
scanf("%s%s%s%s", stu[i].card_num,stu[i].name, stu[i].money,stu[i].mode);
}
//重定向返回
freopen("CON", "r", stdin);
}
//从文件读入菜品信息
void readfood(food *fd){
freopen(FOOD_FILE, "r", stdin);
for(int i=0;i<NUM;i++){
scanf("%s%s%s%s", fd[i].id,fd[i].name,fd[i].price,fd[i].num);
}
freopen("CON", "r", stdin);
}
//从文件读入记录信息
void readrecord(record *re){
freopen(RECORD_FILE, "r", stdin);
for(int i=0;i<NUM;i++){
scanf("%s%s%s%s", re[i].stu_id,re[i].food_id,re[i].food_price,re[i].record_time);
}
freopen("CON", "r", stdin);
}
//保存学生信息
void savefile(student *stu){
//重定向到文件,向文件中输入
freopen(USER_FILE, "w", stdout);
for(int i = 0; i<NUM; i++){
if(strlen(stu[i].card_num)!=0){
printf("%s %s %s %s\n",stu[i].card_num,stu[i].name, stu[i].money,stu[i].mode);
}
}
freopen(CONSOLE, "w", stdout);
}
//保存食物信息
void savefood(food *fd){
freopen(FOOD_FILE, "w", stdout);
for(int i = 0; i<NUM; i++){
if(strlen(fd[i].id) != 0){
printf("%s %s %s %s\n",fd[i].id,fd[i].name, fd[i].price,fd[i].num);
}
}
freopen(CONSOLE, "w", stdout);
}
//保存记录信息
void saverecord(record *re){
freopen(RECORD_FILE, "w", stdout);
for(int i=0;i<NUM;i++){
if(strlen(re[i].stu_id) != 0){
printf("%s %s %s %s\n",re[i].stu_id,re[i].food_id,re[i].food_price,re[i].record_time);
}
}
freopen(CONSOLE, "w", stdout);
}
//================ 管理员功能实现 ================
//注册学生卡,默认激活
void regist(){
char cardnum[20],name[20]; //接收用户输入
int money,mode=0; //标记使用
printf(" 输入卡号:");
scanf("%s",cardnum);
printf(" 输入姓名:");
scanf("%s",name);
printf(" 输入余额:");
scanf("%d",&money);
// 文件指针
FILE* fp = fopen(USER_FILE, "a+");
// 输出到文件
fputs(cardnum, fp); fputs(" ", fp);
fputs(name, fp); fputs(" ", fp);
char str1[20];
itoa(money, str1, 10);
fputs(str1, fp); fputs(" ", fp);
char str2[20];
itoa(mode, str2, 10);
fputs(str2, fp); fputs("\n", fp);
// 关闭文件
fclose(fp);
printf(" 注册成功!\n");
rerun();//重新启动程序
}
//充值
void charge(student *stu){
readfile(stu);
char num[20];
char charge_num[999];
int charge_money=0,flag=0;
printf(" 请输入要充值的卡号:");
scanf("%s",num);
printf(" 请输入充值金额:");
scanf("%s",charge_num);
charge_money=atol(charge_num);
for(int i =0;i<NUM-1;i++){
if(strcmp(stu[i].card_num,num)==0){
charge_money=atol(stu[i].money)+charge_money;
ltoa(charge_money,charge_num,10);
strcpy(stu[i].money,charge_num);
flag=1;
printf(" 充值成功!\n");
break;
}
}
if(flag==0) printf(" 没有该卡!\n") ;
savefile(stu);
rerun();//重新启动程序
}
//挂失
void report_of_loss(student *stu){
readfile(stu);
int flag=-1;//做标记
char num[20];
printf(" 请输入要挂失的卡号:");
scanf("%s",num);
for(int i =0;i<NUM-1;i++){
if(strcmp(stu[i].card_num,num)==0){
flag=i;
strcpy(stu[i].mode,"1");
printf(" 挂失成功!\n");
break;
}
}
if(flag==-1) printf(" 查无此卡,请先注册!\n");
savefile(stu); //将关键信息保存
rerun();//重新启动程序
}
//解挂
void hanging_solutions(student *stu){
readfile(stu);
int flag=-1;
char num[20];
printf(" 请输入要解挂的卡号:");
scanf("%s",num);
for(int i =0;i<NUM-1;i++){
if(strcmp(stu[i].card_num,num)==0){
flag=i;
strcpy(stu[i].mode,"0");
printf(" 解挂成功!\n");
break;
}
}
if(flag==-1) printf(" 查无此卡,请先注册!\n");
savefile(stu);
rerun();//重新启动程序
}
//注销
void del(student *stu){
readfile(stu);
int flag =-1;
char num[20];
printf(" 请输入要注销的卡号:");
scanf("%s",num);
for(int i =0;i<NUM-1;i++){
//找到卡后置空
if(strcmp(stu[i].card_num,num)==0){
flag=i;
strcpy(stu[i].card_num,"");
strcpy(stu[i].name,"");
strcpy(stu[i].money,"");
strcpy(stu[i].mode,"");
printf(" 注销成功!\n") ;
}
}
if(flag==-1) printf(" 查无此卡,请先注册!\n");
savefile(stu);
rerun();
}
//录入菜品
void input(food *fd){
char id[20],name[20],price[20],num[10];
printf(" 输入菜品ID:");
scanf("%s",id);
printf(" 输入菜品名称:");
scanf("%s",name);
printf(" 输入菜品价格:");
scanf("%s",price);
printf(" 输入菜品数量:");
scanf("%s",num);
// 文件指针
FILE* fp = fopen(FOOD_FILE, "a+");
// 输出到文件
fputs(id, fp); fputs(" ", fp);
fputs(name, fp); fputs(" ", fp);
fputs(price, fp); fputs(" ", fp);
fputs(num, fp); fputs("\n", fp);
// 关闭文件
fclose(fp);
printf(" 录入成功!\n");
rerun();
}
//查询菜品
void check(food *fd){
readfood(fd);
char id[20];
printf(" 请输入需要查询的菜品ID:");
scanf("%s",id);
for(int i =0;i<NUM-1;i++){
if(strcmp(fd[i].id,id)==0){
printf(" 菜品ID为:%s",fd[i].id);
printf(" 菜品名称为:%s",fd[i].name);
printf(" 菜品价格为:%s",fd[i].price);
printf(" 菜品数量为:%s\n",fd[i].num);
}
}
rerun();
}
//统计功能 (打印所有菜品信息)
void count(food *fd){
readfood(fd);
int total_num=0,total_money=0;//菜品数量,总销售额
for(int i =0;i<NUM-1;i++){
if(strlen(fd[i].id)!=0){
printf(" 菜品ID为:%s",fd[i].id);
printf(" 菜品名称为:%s",fd[i].name);
printf(" 菜品价格为:%s",fd[i].price);
printf(" 菜品数量为:%s\n",fd[i].num);
total_num+=atoi(fd[i].num);
total_money+=atol(fd[i].num)* atol(fd[i].price);
}
}
printf(" 菜品总数量为:%d\t",total_num);
printf(" 菜品可销售总金额为:%d\n",total_money);
rerun();
}
//================ 学生功能实现 ================
//查余额
void surplus(student *stu,char *num){
readfile(stu);
for(int i =0;i<NUM-1;i++){
if(strcmp(stu[i].card_num,num)==0){
printf(" 账户余额为:%s\n",stu[i].money);
}
}
rerun();
}
//消费记录
void sturecord(record *re,char *num){
readrecord(re);
int flag=-1;
for(int i =0;i<BUFLEN-1;i++){
if(strcmp(re[i].stu_id,num)==0){
flag=i;
printf(" 学生卡号为:%s",re[i].stu_id);
printf(" 购买菜品编号为:%s",re[i].food_id);
printf(" 购买菜品价格为:%s",re[i].food_price);
printf(" 购买时间为:%s\n",re[i].record_time);
}
}if(flag==-1) printf(" 无记录!\n");
rerun();
}
//购物
void purchase(student *stu,food *fd,char *num){
readfile(stu);
readfood(fd);
char stu_id[20];
char food_id[20];
char food_price[20];
char record_time[255];
char ch_fd[10],money[20];
int re_id1=-1,re_id2=-1,flag=0;
//获取时间
time_t t = time( 0 );
char tmpBuf[BUFLEN];
strftime(tmpBuf, BUFLEN, "%Y-%m-%d-%H:%M:%S", localtime(&t)); //格式化时间
for(int i =0;i<NUM-1;i++){
if(strcmp(stu[i].card_num,num)==0){
//找到对应得学生卡后输出菜品
re_id1=i;
for(int j =0;j<NUM-1;j++){
if(strlen(fd[j].id)!=0){
printf(" 菜品ID为:%s",fd[j].id);
printf(" 菜品名称为:%s",fd[j].name);
printf(" 菜品价格为:%s",fd[j].price);
printf(" 菜品数量为:%s\n",fd[j].num);
}
}
//购物选择
printf(" 输入要购买的商品ID:");
scanf("%s",ch_fd);
for(int k =0;k<NUM-1;k++){
if(strcmp(fd[k].id,ch_fd)==0){
//找到菜品后 余额和菜价进行比较
if(atoi(stu[i].money)>atoi(fd[k].price)&&fd[k].num>0){
printf(" 购买成功!\n");
re_id2=k;
savefile(stu);
// 文件指针
FILE* fp = fopen(RECORD_FILE, "a+");
// 输出到文件
fputs(stu[re_id1].card_num, fp); fputs(" ", fp);
fputs(fd[re_id2].id, fp); fputs(" ", fp);
fputs(fd[re_id2].price, fp); fputs(" ", fp);
fputs(tmpBuf, fp); fputs("\n", fp);
// 关闭文件
fclose(fp);
char re_money[20],remun[10];
itoa(atoi(stu[i].money)-atoi(fd[k].price),re_money,10);
strcpy(stu[i].money,re_money);
itoa(atoi(fd[k].num)-1,remun,10);
strcpy(fd[k].num,remun);
savefile(stu);
savefood(fd);
} else printf(" 余额不足,请充值!\n");
}
}
}
}
rerun();//重新启动程序
}
//================ 菜单与模式入口================
//管理模式菜单
int admin_menu(){
int re=0;
printf("========== 管理模式 ==========\n");
printf(" * * * 学生卡相关 * * *\n");
printf(" [---- Press 1 :注册----]\n");// regist
printf(" [---- Press 2 :充值----]\n");// charge
printf(" [---- Press 3 :挂失----]\n");// report_of_loss
printf(" [---- Press 4 :解挂----]\n");// hanging_solutions
printf(" [---- Press 5 :注销----]\n\n");// del
printf(" * * * 菜品相关* * *\n");
printf(" [---- Press 6 :录入菜品----]\n");// input
printf(" [---- Press 7 :查询菜品----]\n");// check
printf(" [---- Press 8 :统计菜品----]\n\n");// count
printf(" 请输入您的选择:");
scanf("%d",&re);
return re;
}
//学生模式菜单
int stu_menu(){
int re=0;
printf("========== 学生模式 ==========\n");
printf(" [---- Press 1 :查询余额----]\n");// surplus
printf(" [---- Press 2 :消费记录----]\n");// record
printf(" [---- Press 3 :购买菜品----]\n");// purchase
printf(" 请输入您的选择:");
scanf("%d",&re);
return re;
}
//管理模式
void admin_mode(student *stu,food *fd){
int admin_password=0,menu_ch=0;
printf(" 请输入管理员密码:");
scanf("%d",&admin_password);
if(admin_password==password){
menu_ch = admin_menu();
switch(menu_ch){
case 1 : fflush(stdin);regist();break;// 注册
case 2 : fflush(stdin);charge(stu);break;// 充值
case 3 : fflush(stdin);report_of_loss(stu);break;// 挂失
case 4 : fflush(stdin);hanging_solutions(stu);break;// 解挂
case 5 : fflush(stdin);del(stu);break;// 注销
case 6 : fflush(stdin);input(fd);break;// 录入
case 7 : fflush(stdin);check(fd);break;// 查询
case 8 : fflush(stdin);count(fd);break;// 统计
}
}else{
printf(" 密码错误!请确认密码后重试。\n\n");
}
admin_mode(stu,fd);//再次载入
}
//学生模式
void stu_mode(student *stu,food *fd,record *re){
readfile(stu);
int stu_ch=0,flag=-1;
char num[20];
printf(" 请输入您的卡号:");
scanf("%s",num);
for(int i =0;i<NUM-1;i++){
if(strcmp(stu[i].card_num,num)==0 && strcmp(stu[i].mode,"0")==0){
flag=i;
stu_ch = stu_menu();
switch(stu_ch){
case 1 : fflush(stdin);surplus(stu,num);break;// 查余额
case 2 : fflush(stdin);sturecord(re,num);break;// 查记录
case 3 : fflush(stdin);purchase(stu,fd,num);break;// 购买菜品
}
}
}
if(flag==-1) printf(" 登录出错,请确认该卡是否已注册或处于挂失状态!\n") ;
rerun();
}
//主菜单显示
int menu(){
int re=0;
printf("======== 食堂管理系统 ========\n");
printf(" [---- Press 1 :管理模式----]\n");
printf(" [---- Press 2 :学生模式----]\n");
printf(" 请输入您的选择:");
scanf("%d",&re);
return re;
}
//重启函数
void rerun(){
//判断是否重新运行本系统
char re_star[2];
printf("\n 目前程序已运行完毕,是否重新启动本程序?(y or else): ");
scanf("%s",re_star);
if (strcmp(re_star,"y")==0){
main();
} else {
system("pause");
exit(0);
}
}
int main(void){
//三个结构体的初始化
student stu[NUM];
food fd[NUM];
record re[BUFLEN];
init(stu,fd,re);
//载入文本文件
readfile(stu);
readfood(fd);
readrecord(re);
printf("\n");
int re_menu=0;
re_menu=menu();
if (re_menu==1){
printf("\n 您将进入管理模式!\n\n");
admin_mode(stu,fd);
} else if(re_menu==2){
printf("\n 您将进入学生模式!\n\n");
stu_mode(stu,fd,re);
}else{
printf(" 输入有误,请重新输入!\n");
fflush(stdin); //清空缓冲区
main();//重新调用初始菜单函数;
}
system("pause");
return 0;
}
五、测试总结
在开始正式测试之前,因为编写程序时需要进行必要的测试,已造成相关数据的变动,本次测试数据及其结果将继续沿用目前已经存在的相关数据。内容介绍如下:
user.txt 文件用来存放学生卡信息
逐列分别代表:卡号;姓名;余额;状态。数据:
001 qqq 101 0
002 wqq 111 0
003 ewq 10 0
food.txt文件用来保存菜品的信息
逐列分别代表:菜号;菜名;金额;数量数据:
001 qwe 10 9
002 qwq 99 1
record.txt文件用来保存购买的信息
逐列分别代表:学生卡号;菜品ID;菜品金额;时间
数据:
001 001 10 2021-03-12-13:17:40
002 001 10 2021-03-12-13:17:53
001 001 10 2021-03-12-13:26:32
003 002 99 2021-03-12-13:44:46
001 002 99 2021-03-12-14:13:21
001 001 10 2021-03-12-14:17:40
001 001 10 2021-03-12-14:24:10
在测试的过程中会对与变动的数据进行截图对比,对非必要对比部分(比如菜单运行)将不再说明。本程序已对用户输入进行检测,会给出输入检测示例。另外,因为本程序涉及函数过多,不再一一测试截图,仅对部分主要功能部分进行测试。
数据已经给啦,测试截图就不贴啦~
六、其他
以上以及博客中含有在校整理字样的博客内容,均是本人本科在校学习期间所写的代码,源文件以及数据文件等在个人主页资源区可以获取。本人水平很低,大佬轻喷。整理出来是为了帮助初学者学习的过程中,在有需要的情况下能够有所参考。再次声明:仅供学习交流使用。大家有什么问题,欢迎留言~