- 课题描述
- 编制一个程序,火车票订票的业务活动包括:车次查询、订票、退票、用户管理等。
- 需求分析
- 用户信息包括用户姓名、身份证号、用户电话、用户所购列车号、订单号;列车信息包括:列车车站号、车票起点、车票终点、出发时间、到达时间、票价、票数等基本信息。
- 软件需要实现以下功能:
- (1)录入:可以录入车次(车次号、车站1、车站2...、余票)、客户等数据;
- (2)查询车次:车次及分段余票信息;
- (3)订票业务:根据客户提出的要求(车次、起点、终点、订票数额)查询票额情况,若尚有余额,则为客户办理订票手续;若余票额少于订票额,则进入排队预约。
- (4)退票业务:为客户办理退票手续,然后查询该车次是否有人预约登记,首先满足排在第一的客户,若所退票额满足要求,则办理订票手续,否则依次查询其他排队预约的客户。
设计思路分析:首先大家要清楚,C语言是面向过程的一门语言,也是更加偏向于底层的一门设计语言,所以我们在设计之初,要先分析程序的需求,联系生活实际的同时建立在每个对象的基础上去思考程序应当实现什么功能。
火车站服务台端:作为火车站服务的层面,我们是向用户提供服务的,我们首先应该要具备的一些基本信息:车站号,车票起点,车票终点,出发的时间,预计到达的时间,票价,票数。所以我们把火车服务端结构体设计如下:
typedef struct train { int stationId; //车站号 char from[STR_LEN]; //车票起点 char to[STR_LEN]; //车票终点 char stime[16];//出发时间 char rtime[16];//到达时间 int money; //票价 int ticket;//票数 }Train;
用户端:作为用户是接受火车服务端提供的服务的,每个用户都应该有自己的专属个人基本信息:姓名,身份证号,用户手机号,用户所购的列车号,用户的订单编号等.
typedef struct user { char name[STR_LEN];//用户姓名 char id[STR_LEN];//身份证号 char tele[STR_LEN];//用户电话 int trainId;//用户所购的列车号 int order;//订单编号 }User;
接下来我们采用链表的结构对用户端和火车服务器端分别进行控制:
typedef struct TrainNode //定义列车节点 { Train data; struct TrainNode* next; }TN; typedef struct UserNode //定义用户链表 { User data; struct UserNode* next; }UN;
设计需要的功能函数分析:在设计之前,我们需要理清一下思路,结合一下大家在网上订票的实际情况,我们来看看这个需要完成什么。
1.当我们首先进入某个可以支持火车票的线上订票app平台,进入之后,首先进入界面后映入眼帘的应当是欢迎来到订票系统的几个大字吧,然后再提供几个选项给用户和后台人员供选择他们需要的功能。
2.作为买票的用户,毋庸置疑应当有一个函数接口来给我们提供订票服务的。大家设想,当我们去订票的时候,我们一般习惯会根据列车的终点站,出发站,列车号这是三个最基本的信息,有了这三个信息,就可以找出对应我们所需要的那辆列车,当我们查到我们需要的列车过后,又可能这个列车票已售空,所以我们还需要一个接口函数来判断票数,当票数不为空时,我们就可以成功地进入购票支付界面,在支付之前,我们需要输入提供我们的个人信息。完成订票过后,如果我们突然临时有情况想要退票,那么我们还应该完善一个退票服务给用户,当然上述的退票系统和订票系统都是双向的,既要面对服务端也要面对客户端,服务端为用户提供用户需要的查询信息等,客户端记录用户出行信息,修改列车信息等。
3.作为后台服务端,我们的任务就是录入列车的信息,录入列车信息过后,可能会出现一些临时需要修改的情况,还需要再提供一个修改列车信息的函数接口。
4.提供两个查询信息的接口,一个用于查询列车信息,另一个用于查询用户信息。
5.提供两个显示接口,一个用于显示列车信息,另一个用于显示用户信息。
6. 由于我们需要采用文件的方式来进行,那么我们需要分别提供,文件数据载入程序,录入信息保存至文件。
train.h
#pragma once #include"stdio.h" #include"conio.h"//调用控制台输入输出函数头文件 #include"string.h" #include"time.h" #include"stdlib.h" #define STR_LEN 50//字符串长度 typedef struct train { int stationId; //车站号 char from[STR_LEN]; //车票起点 char to[STR_LEN]; //车票终点 char stime[16];//出发时间 char rtime[16];//到达时间 int money; //票价 int ticket;//票数 }Train; typedef struct user { char name[STR_LEN];//用户姓名 char id[STR_LEN];//身份证号 char tele[STR_LEN];//用户电话 int trainId;//用户所购的列车号 int order;//订单编号 }User; typedef struct TrainNode //定义列车节点 { Train data; struct TrainNode* next; }TN; typedef struct UserNode //定义用户链表 { User data; struct UserNode* next; }UN; void menu();//菜单显示 void orderTicket(TN* s, UN* u); //订票服务 void refundTicket(TN* s, UN*& u);//退票服务 void search(TN* s);//列车信息查找 void search_t_id(TN* s);//按列车号查询 void search_t_from(TN* s);//按发车站查询 void search_t_to(TN* s);//按终点站查询 void updateInfo(TN* s);//列车信息修改 void except_id(TN* s, TN* l);//列车号录入查重 void except_update_id(TN* s);//修改列车号查重 void Judge_ticket(TN *s);//票数非负判断 void Judge_money(TN *s);//票价非负判断 void all_show(TN* s);//查询全部列车 void allp_show(TN* s, UN* u);//查询用户信息 void Info(TN *s);//列车信息显示 void luru(TN* s);//文件信息录入 void load(TN* s);//文件数据载入 void save(TN* s);//文件保存
test.cpp
#define _CRT_SECURE_NO_WARNINGS #include"train.h" int main() { TN* s;//定义服务端server int n; UN* u;//定义用户端user s = (TN *)malloc(sizeof(TN)); u = (UN *)malloc(sizeof(UN));//各开辟好一个头结点,不存储有效数据 s->next = NULL; u->next = NULL;//next置为NULL do { system("date/t");//给定日期 system("color F3");//设置默认控制台前景和背景颜色,可以根据自己喜欢的颜色修改 menu(); scanf("%d", &n); system("cls");//清除屏幕 switch (n) { case 1: luru(s); break; case 2: search(s); break; case 3: allp_show(s, u); break; case 4: updateInfo(s); break; case 5: orderTicket(s, u); break; case 6: refundTicket(s, u); break; case 7: save(s); break; case 8: load(s); break; case 9: exit(0); break; default: continue;//输入错误用continue跳出本次循环 } } while (1); return 0; }
train.cpp
#define _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS #include"train.h" void menu()//菜单函数 { printf("\n\t-----------------------欢迎来到火车订票系统-----------------------\n"); printf("\n\t\t\t*********************************\n");//注意\t,跳过8个空格,这里应用到\t仅仅只是为了界面的美观整齐 printf("\t\t\t\t1.录入列车信息\n\t\t\t\t2.查询列车情况\n\t\t\t\t3.查询用户信息\n\t\t\t\t4.修改列车信息\n\t\t\t\t5.订票服务\n\t\t\t\t6.退票服务\n\t\t\t\t7.保存已录入的信息\n\t\t\t\t8.读取已有的列车信息\n\t\t\t\t9.退出系统\n\t\t\t\t"); printf("\n\t\t\t*********************************\n\t\t\t"); printf("输入您所要执行的功能(0-8):"); } void except_id(TN *p, TN* u)//录入列车号查重 { TN* q; q = u;//用于存放服务端头结点 while (q != NULL) { if (p->data.stationId == q->data.stationId)//找到列车号相等的则提示服务端人员重新输入 { printf("\t当前列车班次已存在,请重新输入:"); scanf("%d", &p->data.stationId); except_id(p, u); } else q = q->next;//不断往后迭代 } } void Judge_ticket(TN *u)//票数非负判断 { if (u->data.ticket < 0) { printf("\t票数输入有误,请重新输入: "); scanf("%d", &u->data.ticket); Judge_ticket(u);//输入错误再次调用提示 } } void Judge_money(TN* u) //票价非负判断 { if (u->data.money < 0) { printf("\t票价输入有误,请重新输入: "); scanf("%d", &u->data.money); Judge_money(u);//输入错误再次调用提示 } } void luru(TN* u)//文件信息录入 { TN *p, *q; q = u;//用于存放服务端头结点 while (q->next != NULL) { q = q->next; }//利用循环去找到尾结点 p = (TN *)malloc(sizeof(TN));//开辟一个新结点 printf("\n\t---------------------------------列车信息录入---------------------------------\n"); if (p == NULL) { printf("录入出错!"); exit(0); }//p等于NULL则开辟空间失败 printf("\n\t1.请输入列车号:");//首先输入列车号,因为列车号是每个火车的专有属性 scanf("%d", &p->data.stationId); except_id(p, u);//录入的列车号查重,防止列车号相同 printf("\t2.请输入起点站名称:"); scanf("%s", &p->data.from); printf("\t3.请输入终点站名称:"); scanf("%s", &p->data.to); printf("\t4.请输入列车出发时间(时分格式为00:00):"); scanf("%s", &p->data.stime); printf("\t5.请输入列车到达时间(时分格式为00:00):"); scanf("%s", &p->data.rtime); printf("\t6.请输入票价:"); scanf("%d", &p->data.money); Judge_money(p);//输入的票价要判断,防止输入操作出现错误 printf("\t7.请输入票数:"); scanf("%d", &p->data.ticket); Judge_ticket(p);//输入的票数要判断,防止输入操作出现错误 p->next = NULL;//最后把next置为空 q->next = p;//把新开辟的结点链接到尾结点上 q = p;//最后更新一下尾节点位置 printf("\t录入成功!\t\n"); } void orderTicket(TN* s, UN* u) //订票服务 { TN *p;//用来存放服务端头结点 UN *q;//定义用户端结点 int n; p = s; int t_id;//保存需要输入的列车号 printf("\n\t---------------------------------火车票订单填写---------------------------------\n"); printf("\t请输入您需要预订的列车号:"); scanf("%d", &t_id);//首先输入列车号 while (p != NULL && p->data.stationId != t_id)//循环终止条件为找到列车号相同的列车或者走到尾节点 { p = p->next;//不断循环迭代 } if (p == NULL)//当为空结束上面循环时,说明在录入的文件中没有该列车 { printf("\t**暂无相关车票可预订!**"); } else//没有为空结束时,说明找到了符合预定的列车号 { if (p->data.ticket <= 0)//如果该列车票数不足,那么提示用户已售空 { printf("\t**该列车车票已经售空**\n"); } else { q = u; while (q->next != NULL) { q = q->next; }//把录入的用户链接到尾结点上 UN* r = (UN *)malloc(sizeof(UN)); printf("\n\t#####请按提示输入您的个人信息#####\n"); printf("\t请输入您的姓名:"); scanf("%s", &r->data.name); printf("\t请输入您的身份证号码:"); scanf("%s", &r->data.id); printf("\t请输入您的手机号码:"); scanf("%s", &r->data.tele); r->data.trainId = t_id; p->data.ticket = p->data.ticket - 1;//用户订票成功后需要将该列车总票数-1 srand((int)time(NULL));//利用时间戳的方式来指定随机数 n = rand() % 8999 + 1000;//用随机数的方式设计一个四位数的订单编号 r->data.order = n; printf("\t订票成功,您已成功预订一张列车号为%d的车票,", r->data.trainId); printf("订单编号为%d\n", r->data.order); r->next = NULL; q->next = r; q = r; } } } void refundTicket(TN* s, UN*& u)//退票服务 注意这里的用户端需要传引用 { TN *p; UN *q, *r;//定义用户端结点 char id[STR_LEN];//定义身份证号 int ord;//定义订单编号 p = s;//定义服务端头结点 r = u;//将r置为用户端的头结点 int input_t_id;//定义购票时的列车号 printf("\n\t---------------------------------火车票退票界面---------------------------------\n"); printf("\t请输入您需要退票的列车号:"); scanf("%d", &input_t_id); printf("\t请输入您的身份证号:"); scanf("%s", &id); printf("\t请输入您的订单编号:"); scanf("%d", &ord); //以上输入的身份证号订单编号,都是用户所独有专有的信息,不可能会重复 while (r != NULL) { if (strcmp(r->data.id, id) == 0 && input_t_id == r->data.trainId && ord == r->data.order)//注意身份证号要用strcmp函数去比较 { printf("\t您当前的订票信息如下:\n"); printf("\t名字:%s\n", r->data.name); printf("\t电话号码为:%s\n", r->data.tele); printf("\t列车号码为:%d\n", r->data.trainId); break;//找到完全匹配的用户时,把用户其余信息打印,然后跳出该循环 } else { r = r->next;//不断往后迭代 } } if (r == NULL)//当上述循环以NULL结束时,说明没有找到该用户的信息 { printf("\t**查询不到您的订票信息**\n"); } else//不是以空结束的循环,说明找到了用户的购票信息 { while (p != NULL && p->data.stationId != input_t_id) { p = p->next;//利用该循环去迭代找出用户订购的列车 } if (p == NULL)//如果以空结束循环说明没有该列车 { printf("查询不到该车票信息\n"); } else//找到对应的列车号后 { p->data.ticket += 1;//将列车票票数+1 q = (UN *)malloc(sizeof(UN)); q = r; q->next = r->next; free(r);//将此退票用户结点free掉 } printf("\t**退票成功,感谢使用!**\n"); } } void Info(TN *s)//列车信息显示 { printf("\t%5d", s->data.stationId); printf("%8s", s->data.from); printf("%8s", s->data.to); printf("%10s", s->data.stime); printf("%15s", s->data.rtime); printf("%15d", s->data.money); printf("%15d\n", s->data.ticket); } void search_t_id(TN* s)//按列车号查询 { int num;//定义列车号 TN* p; p = s;//定义列车头结点 printf("请输入您需要查找的列车信息的列车号:"); scanf("%d", &num); printf("\n\t\t\t\t******-----查询结果-----******\n"); printf("\t列车号\t发车站\t到达站\t发车时间\t到达时间\t票价(元)\t票数(张)\n"); while (p) { if (p->data.stationId == num)//列车号一样时跳出循环 { Info(p); break; } p = p->next; } if (p == NULL) { printf("\t\t未找到该列车号的信息!\n"); } } void search_t_from(TN* s)//按发车站查询 { TN *p; char pstart[STR_LEN];//定义始发站 p = s->next; int flag = 0; printf("请输入您需要查找的列车信息的始发站:"); scanf("%s", &pstart); printf("\n\t\t\t\t******-----查询结果-----******\n"); printf("\t列车号\t发车站\t到达站\t发车时间\t到达时间\t票价(元)\t票数(张)\n"); while (p)//p不为空时进入循环 { if (strcmp(p->data.from, pstart) == 0)//发车站相等时进入该if语句 { Info(p); flag = 1;//找到发车站相等的列车将flag置为1 if (p->next == NULL)//如果p->next等于NULL则跳出循环 break; else p = p->next;//next不为空则继续迭代 } } if (p == NULL || flag == 0)//为空时或者flag等于0时 { printf("\t\t\t.......未找到该列车信息!\n"); } } void search_t_to(TN* s)//按终点站查询 { TN *p; char preach[STR_LEN];//定义终点站 p = s->next; int flag = 0; printf("请输入您需要查找的列车信息的终点站:"); scanf("%s", &preach); printf("\n\t\t\t\t******-----查询结果-----******\n"); printf("\t列车号\t发车站\t到达站\t发车时间\t到达时间\t票价(元)\t票数(张)\n"); while (p) { if (strcmp(p->data.to, preach) == 0)//终点站相等时进入if循环 { Info(p); flag = 1;//修改flag的值 } if (p->next == NULL) break; else p = p->next; } if (p == NULL || flag == 0) { printf("\t\t\t.......未找到该列车信息!"); } } void all_show(TN* s)//查询全部列车 { TN* p; p = s->next; printf("\n\t\t\t\t******-----查询结果-----******\n"); printf("\t列车号\t发车站\t到达站\t发车时间\t到达时间\t票价(元)\t票数(张)\n"); if (p == NULL) { printf("\t\t\t.......未查询到任何列车信息!"); } while (p != NULL) { Info(p); p = p->next; } } void allp_show(TN*s, UN* u)//查询用户信息 { UN *q, *r; r = u->next; printf("\n\t\t\t\t******-----查询结果-----******\n"); printf("\t列车号\t姓名\t身份证号\t\t电话号码\t\t订单编号\n"); if (r == NULL) { printf("\t\t\t未查询到任何用户信息!"); } while (r != NULL) { printf("\t%5d", r->data.trainId); printf("%8s", r->data.name); printf("%21s", r->data.id); printf("%17s", r->data.tele); printf("%18d\n", r->data.order); r = r->next; } } void search(TN* s)//列车信息查找 { int num;//定义查询方式 printf("\n\t---------------------------------列车信息查询---------------------------------\n"); printf("\t1.按列车号查询\n\t2.按始发站查询\n\t3.按终点站查询\n\t4.查询所有列车信息\n\n"); printf("\t请输入您的查询方式:"); scanf("%d", &num); printf("\n\t---------------------------------————————-----------------------------\n"); if (num == 1) search_t_id(s); else if (num == 2) search_t_from(s); else if (num == 3) search_t_to(s); else if (num == 4) all_show(s); else printf("\t\t输入错误!!\n"); } void except_update_id(TN *s)//修改列车号查重 { TN *q; TN *m; q = s->next; while (q) { if (s->data.stationId == q->data.stationId) { printf("\t当前列车班次已存在,请重新输入:"); scanf("%d", &s->data.stationId); except_update_id(s); } else q = q->next; } } void updateInfo(TN* s)//列车信息修改 { int num;//定义需要修改的列车号 int n;//定义需要修改的信息 TN* p; p = s->next; if (p == NULL) { printf("\t**暂时没有可以修改的列车信息**\n"); } else { printf("请输入需要修改列车信息的列车号:"); scanf("%d", &num); while (p->data.stationId != num) { p = p->next; if (p == NULL) { printf("找不到该列车信息"); break; } } if (p) { printf("\n\t---------------------------------列车信息修改---------------------------------\n"); printf("\t1.列车号\n\t2.起始站\n\t3.终点站\n\t4.出发时间\n\t5.到达时间\n\t6.票价\n\t7.票数\n"); printf("\t---------------------------------——————---------------------------------\n"); printf("\t请输入您要修改的信息编号:"); scanf("%d", &n); switch (n) { case 1: printf("\t请输入变更后的列车号:"); scanf("%d", &p->data.stationId); except_update_id(p);//列车号查重 break; case 2: printf("\t请输入变更后的起始站:"); scanf("%s", &p->data.from); break; case 3: printf("\t请输入变更后的终点站:"); scanf("%s", &p->data.to); break; case 4: printf("\t请输入变更后的出发时间(时分格式为00:00):"); scanf("%s", &p->data.stime); break; case 5: printf("\t请输入变更后的到达时间(时分格式为00:00):"); scanf("%s", &p->data.rtime); break; case 6: printf("\t请输入变更后的票价:"); scanf("%d", &p->data.money); Judge_money(p);//票价判负 break; case 7: printf("\t请输入变更后的票数:"); scanf("%d", &p->data.ticket); Judge_ticket(p);//票数判负 break; default: printf("\t输入错误!\n"); } if (n >= 1 && n <= 7)//如果n输入合法则修改成功 printf("\t**修改成功**\n"); } } } //文件在读写之前应该先打开文件,在使用结束之后应该关闭文件。 //在编写程序的时候,在打开文件的同时,都会返回一个FILE*的指针变量指向该文件,也相当于建立了指针和文件的关系。 //ANSIC 规定使用fopen函数来打开文件,fclose来关闭文件 void load(TN* s)//文件数据载入程序 { TN *r; FILE *fp; s->next = NULL; r = s; if ((fp = fopen("train", "rb")) == NULL)//rb只读,为了输入数据,打开一个二进制文件 { printf("\n\t********文件打开失败!*********\n"); } else { printf("\n\t========文件数据导入成功!=========\n"); while (!feof(fp))//feof的用途:是读取文件结束了,判断是不是遇到文件末尾而结束的 { TN* p = (TN*)malloc(sizeof(TN)); if (fread(p, sizeof(TN), 1, fp) != 1)//fread二进制读入 break; else { p->next = NULL; r->next = p; r = p; } } } fclose(fp); } void save(TN* s)//录入数据进行文件保存 { TN *p; FILE *fp; p = s->next; if ((fp = fopen("train", "wb")) == NULL)//wb只写 { printf("\t********文件打开失败!*********\n"); exit(0); } else printf("\t========文件保存成功!=========\n"); while (p)//p不为空时继续写入到文件 { char arr[1024] = { 0 }; sprintf(arr, "%d-%s-%s-%s-%s-%d-%d\n", p->data.stationId, p->data.from, p->data.to, p->data.stime, p->data.rtime, p->data.money, p->data.ticket); fwrite(arr,1, strlen(arr), fp);//二进制的形式写入到文件中 p = p->next; } fclose(fp); }
上述代码是在VS下进行测试的,分模块进行的编写,当然还存在很多可以进一步改进的地方,比如可以再加一些内容进行丰富,比如可以添加车票的价位档次等信息