目录
实现功能
整体概述
系统结构
主要功能模块实现
身份验证
信息遍历
查找航班信息
编辑航班信息
整理信息顺序
预订航班
小结
实现功能:
通过此系统可以实现如下功能:(1)录入:管理员用户可以录入航班情况,数据存储在一个数据文件中;(2)遍历:可以查看某一类信息的所有数据如航班信息、订单信息等;(3)查询:可以查询某个航线的情况,如输入航班号来查询起降时间、起飞抵达城市、航班票价、票价折扣、航班是否满仓;也可以输入起飞抵达城市,查询飞机航班情况;(4)订票:普通用户可以订票,订单相关数据会存储在数据文件中,客户资料有姓名,证件号,订票数量及航班情况,订单要有编号;(5)退票: 可退票,退票后修改相关数据文件;(6)修改:当航班信息改变可以修改航班数据文件。
整体概述:
本系统为实现信息的增删改查等功能的应用程序。采用的开发环境为codeblocks,系统环境为windows10。本系统使用的数据结构为结构体数组,相关数据文件的存储方式为使用txt文件存储。本系统实现对数据文件的修改基本思路为:先读取计算机硬盘中的数据文件内容并将其以结构体数组的方式存入计算机内存,修改内容时首先修改的是结构体数组,修改完毕后将修改后的结构体数组重新写入数据文件(覆盖原文件)。
本系统设计思路为,首先通过身份验证用户的身份,二者所能使用的功能与权限不同;验证通过后,根据具体用户的身份系统会提供不同的操作界面,用户可以根据自己的实际需求使用具体功能包括查找航班信息、添加、删除、修改航班信息、整理信息顺序以及预订、退订航班等等操作。
系统结构:
经过分析,本系统的整体结构示意如下:
主要功能模块实现:
本系统使用的头文件为以下三个:
#include#include#include
身份验证
用户在使用本系统时需要输入用户名和密码验证用户身份来取得相应的使用本系统的权限。相关用户信息存放在userinfo.txt中。两类用户分别为管理员和普通用户,系统先将使用者输入的用户信息与数据库中的对应信息作匹配,若匹配成功则进一步判断用户类型。若使用者输入的信息和数据库中的所有信息均不匹配,则计数加一且系统会提示用户重新输入,计数达到三时系统会提示使用者无权使用本应用并自动退出程序。
主要实现代码:
/*打开用户信息文件并读取所有用户信息*/if((user_fp=fopen(".\\datafiles\\userinfo.txt","r"))==NULL){printf("数据读取失败!请检查“userinfo.txt”是否存在或路径是否正确!");//若文件位置错误或不存在Sleep(1000);exit(0);}user=user_info_readin(user_fp);//读取用户信息并将其写入用户信息结构体数组fclose(user_fp);/*将使用者输入的用户信息与所有用户信息进行匹配并验证用户类型*/for(i1=1;i1<=3;i1++){printf("用户名:");scanf("%s",usn);printf("密码:");scanf("%s",psw);for(i=0;i<user_num;i++){if(strcmp(usn,user[i].username)==0&&strcmp(psw,user[i].password)==0){un=i; //全局变量un,用于在其他函数中匹配用户信息printf("登录成功!当前身份:");if(user[i].id==1){//根据用户信息的id选择跳转到指定界面printf("管理员\n");Sleep(1000);admt_menu();//调用管理员操作界面函数}else if(user[i].id==0){printf("普通用户\n");Sleep(1000);user_menu();//调用普通用户操作界面函数}break;}}if(strcmp(usn,user[i].username)==0&&strcmp(psw,user[i].password)==0)break;if(i1==3){printf("验证失败!请先获取用户信息后再登录");//用户输错三次信息后系统提示Sleep(1000);exit(0);}printf("\n登录失败!用户名或密码错误\n您还有%d次输入机会\n",(3-i1));}
用户信息文件:
*该部分数据需要使用者在程序之外自行设定
运行示例:
普通用户—登录成功
登录失败
信息遍历(以航班信息为例)
信息管理系统最基础的一个功能就是对于其主要信息的遍历,本系统为航班信息管理系统,最主要的信息自然就是航班信息。要实现航班信息的遍历,也就是查看全部航班信息,首先需要一个现有航班的航班信息数据库,本系统使用的航班信息数据格式示例如下:
*实际文件没有表头信息,这里为了方便大家理解,展示的是预览文件。另外两个数据文件同理
同时为了在程序中将这些数据展示出来,还需要定义一个航班信息结构体数组(也就是航班信息顺序表)来保存每一条航班信息。结构体变量可根据实际的航班信息来定义,本系统定义的航班信息结构体格式如下:
typedef struct Flight_info{ //定义航班信息结构体int num;//航班号char time_s[6];char time_e[6]; //起降时间char city_s[20];char city_e[20];//起落城市float price;//票价float discount; //折扣char if_full; //是否满座}Flight_info;
定义一个全局变量,指向航班信息结构体数组的指针:
Flight_info *flight;//定义指向航班信息结构体数组的指针
定义读文件函数用于读取数据库中的数据并将其写入该结构体数组:
Flight_info* flight_info_readin(FILE* fp){//读取航班信息 并将其写入结构体数组int i;static Flight_info flight[MAX];flight_num=0; //每次调用函数时重新记录数量for(i=0;!feof(fp);i++){fscanf(fp,"%d %s %s %s %s %f %f %c",&flight[i].num,&flight[i].time_s,&flight[i].time_e,&flight[i].city_s,&flight[i].city_e,&flight[i].price,&flight[i].discount,&flight[i].if_full);//读取每一条航班信息数据flight_num++;//令航班信息数加一}flight_num--;return flight;//返回航班信息结构体数组的首元素地址}
遍历航班信息时,系统会调用相应函数来实现此功能。首先程序需要打开对应文件,然后再调用遍历信息的函数,主要代码如下:
/*打开文件并读取数据信息*/FILE *f_i_fp; //flight_info_filepointer即航班信息文件指针if((f_i_fp=fopen(".\\datafiles\\flightinfo.txt","r"))==NULL){//若数据文件位置错误或不存在printf("数据读取失败!请检查“flightinfo.txt”是否存在或路径是否正确!");Sleep(1000);exit(0);}flight=flight_info_readin(f_i_fp);//调用上面提到的函数将航班信息写入结构体数组fclose(f_i_fp);/*遍历航班信息的函数*/void flight_info_checkall(Flight_info* flight){ //显示全部航班信息int i;system("cls");printf("\n-------------------------------------------全部航班信息---------------------------------------------\n\n");printf("航班号起飞时刻 落地时刻 始发城市终点城市票价折扣是否满座\n");for(i=0;i<flight_num;i++)printf("%-10d%-15s%-15s%-20s%-20s%-10.2f%-10.2f%-10c\n",flight[i].num,flight[i].time_s,flight[i].time_e,flight[i].city_s,flight[i].city_e,flight[i].price,flight[i].discount,flight[i].if_full);}
运行示例:
遍历航班信息
查找航班信息
不仅是全部信息的遍历,查找指定信息的功能也非常重要。本系统为使用者提供了:指定航班号查找、指定始发城市查找和指定终点城市查找三种查找航班信息的方式。本帖以指定航班号查找为例解释一下实现查找功能的原理。实现三种查找方式的原理相类似,因此我将其拆分成三个部分,分别为整体框架、查找函数和输出显示函数。在第一个部分,系统接收用户输入的航班号并将其传递给第二部分进行查找匹配,再将查找的结果值传递给第三部分。这样一来,另外两种查找方式只需要在这基础上进行简单的改动就可以实现了。既简化了工作又保证了代码的一致性,便于后续维护。主要代码如下:
/*1.输入航班号查找航班信息并输出*/printf("请输入要查找的航班号:");scanf("%d",&n);f_info=search_num(flight,n);//将用户输入的航班号作实参,调用按航班号查找航班的函数if(f_info==NULL){printf("未查找到该航班号信息!");Sleep(1000);break;}system("cls");printf("\n航班号:%d\n",n);printf("\n-----------------------------------------查找到的航班信息-------------------------------------------\n\n");printf("+航班号+起飞时刻 落地时刻 始发城市终点城市票价折扣是否满座\n");result_print(f_info); //输出查找结果/*2.按航班号查找航班的函数*/Flight_info* search_num(Flight_info* flight,int n){ //按照航班号查找,查找整个信息表int i;for(i=0;inum,f_info->time_s,f_info->time_e,f_info->city_s,f_info->city_e,f_info->price,f_info->discount,f_info->if_full);}
运行示例:
查找失败时
查找成功
编辑航班信息
一个信息管理系统的管理人员,肯定少不了对信息进行编辑的需求。通过本系统对航班信息进行编辑有三种方式,分别为添加、删除和修改航班信息。其中添加信息的操作较为简单,使用fopen函数打开文本文件时,选择打开方式为“追加(append)”即可在原数据末尾加上新添加的航班信息。实现添加信息的主要代码如下:
n=flight_num;system("cls");printf("\n-------------------------------------------添加航班信息---------------------------------------------\n\n");do{//这里设置循环语句目的是检测添加的航班号是否符合规定printf("1.请输入航班号:");scanf("%d",&(flight+n)->num);fg=0; //用于判断是否需要循环输入for(i=0;itime_s);printf("3.请输入落地时间:");scanf("%s",&(flight+n)->time_e);printf("4.请输入始发城市(格式:英文名字,首字母大写):");scanf("%s",&(flight+n)->city_s);printf("5.请输入终点城市:");scanf("%s",&(flight+n)->city_e);printf("6.请输入航班票价:");scanf("%f",&(flight+n)->price);printf("7.请输入票价折扣:");scanf("%f",&(flight+n)->discount);printf("8.航班是否满座?(Y表示满座,N表示未满)");getchar();//输入char之前需要用getchar清除缓存中的换行符scanf("%c",&(flight+n)->if_full);flight_num++;fprintf(f_i_fp,"%d %s %s %s %s %.2f %.2f %c\n",flight[n].num,flight[n].time_s,flight[n].time_e,flight[n].city_s,flight[n].city_e,flight[n].price,flight[n].discount,flight[n].if_full);//将待添加的信息追加在数据文件的末尾
运行示例:
添加航班信息
重新遍历航班信息,最后一行为新添加的信息
航班信息的删除、修改功能的实现与添加相类似但方法并不相同。本程序实现对信息的删除/修改原理为:先将结构体数组中的指定信息删除/修改,之后通过“写出(write)”方法打开数据文件并将修改后的信息写入文件。*通过这种方式写入文件,其实是删除原文件的内容后再写入新内容,相当于使用新数据覆盖了原数据。虽然这并不是一个好的方法,面对大量的数据时,这种方法可能会消耗较多的资源和时间,但遗憾的是笔者水平有限,只能采取这种方式修改数据文件。相关代码如下:
将结构体数组的内容写入到数据文件中的函数:
void flight_info_writeout(Flight_info* flight){//将顺序表中的航班信息输出,写入到数据文件中,通过此函数实现对航班信息的修改int i;FILE* f_i_fp;if((f_i_fp=fopen(".\\datafiles\\flightinfo.txt","w"))==NULL){printf("数据读取失败!请检查“flightinfo.txt”是否存在或路径是否正确!");Sleep(1000);exit(0);}for(i=0;i<flight_num;i++)fprintf(f_i_fp,"%d %s %s %s %s %.2f %.2f %c\n",flight[i].num,flight[i].time_s,flight[i].time_e,flight[i].city_s,flight[i].city_e,flight[i].price,flight[i].discount,flight[i].if_full);fclose(f_i_fp);}
实现删除功能的主要代码:
for(i=n;inum=(flight+i+1)->num;strcpy(((flight+i)->time_s),((flight+i+1)->time_s));strcpy(((flight+i)->time_e),((flight+i+1)->time_e));strcpy(((flight+i)->city_s),((flight+i+1)->city_s));strcpy(((flight+i)->city_e),((flight+i+1)->city_e));(flight+i)->price=(flight+i+1)->price;(flight+i)->discount=(flight+i+1)->discount;(flight+i)->if_full=(flight+i+1)->if_full;}//将待删除信息之后的每一条信息的每一个子信息赋值给前一条信息的对应子信息flight_num--;//航班信息数减一flight_info_writeout(flight); //将删除信息后的顺序表重新输出,写入到数据文件(覆盖原文件)
运行示例:
删除航班信息
删除之后(对比上一张图)
实现航班信息修改的原理与删除相类似,都是先对结构体数组中某一元素的若干成员变量进行改动,然后再将其覆写到原数据文件中以实现对数据的修改和更新。有一点区别在于,修改航班信息往往是对某一条航班信息的某一个项目进行修改,而不是对于整条信息进行“修改”。例如xx号航班的起飞时刻发生了改变,需要修改;又或者是另一趟航班的票价或折扣发生了变化,需要对其进行修改。在这种情况下我们就可以使用switch—case函数来选择指定的项目,然后再单独进行修改即可。此外,不同于普通数组的元素,对于结构体数组某一元素的成员变量,是可以直接赋值的。关键代码如下:
printf("请输入需要修改的项目的序号:");scanf("%c",&k1);switch(k1){case '1':printf("航班号不可修改!\n");break;case '2':printf("请输入修改后的起飞时刻:");scanf("%s",time_s_m);strcpy((flight+n)->time_s,time_s_m);break;case '3':printf("请输入修改后的降地时刻:");scanf("%s",time_e_m);strcpy((flight+n)->time_e,time_e_m);break;case '4':printf("请输入修改后的始发城市:");scanf("%s",city_s_m);strcpy((flight+n)->city_s,city_s_m);break;case '5':printf("请输入修改后的终点城市:");scanf("%s",city_e_m);strcpy((flight+n)->city_e,city_e_m);break;case '6':printf("请输入修改后的航班票价:");scanf("%f",&price_m);(flight+n)->price=price_m;break;case '7':printf("请输入修改后的票价折扣:");scanf("%f",&discount_m);(flight+n)->discount=discount_m;break;case '8':printf("请输入修改后的满座情况(Y表示满座,N表示未满):");scanf("%c",&if_full_m);(flight+n)->if_full=if_full_m;break;default:printf("需要正确选择项目对应序号!");break;}
运行示例:
修改航班信息
修改信息之后(对比上一张图)
整理信息顺序
本系统提供了三种对航班信息进行排序的方式,分别为按航班号升序排序,按起点城市名升序排序和按终点城市名升序排序。第一、三种排序采用的是简单排序之冒泡排序法,第二种排序采用的是快速排序法,在这里以第二种排序为例简单解释一下本系统实现该功能的原理。快速排序的大致思路为:在待排序序列(如一个数组r[n])中选择一个记录(通常选择首元素r[0])作为中间变量key,然后开始排序,把所有小于中间变量key的记录通过交换置于其左边称作左子序列,所有大于中间变量key的记录置于其右边称作右子序列,然后再分别以左子序列和右子序列为新的待排序序列,重复以上流程,也就是递归,直到不再产生新的子序列,排序完毕。以下为实现该功能的主要代码:
void sort_city_s_up(int begin,int end){ //按始发城市名升序排序,快速排序法void flight_info_swap(int,int);if(begin>=end)return;char key[20];//定义key作为中间变量int left,right;left=begin;right=end;strcpy(key,(flight+begin)->city_s); //将起始值赋给中间变量keywhile(end>begin){while(strcmp((flight+end)->city_s,key)>=0&&end>begin)end--;flight_info_swap(begin,end);while(strcmp((flight+begin)->city_s,key)begin)begin++;flight_info_swap(end,begin);//循环完毕后将两条航班信息相交换}sort_city_s_up(left,begin-1);//左边的子数组继续进行排序sort_city_s_up(end+1,right);//右边的同理flight_info_writeout(flight);//排序完成后将数据覆写入数据文件return;}
运行示例:
按起点城市名升序排序
排序完成之后(对比上一张图)
预订航班
预定航班功能的实现原理与添加航班信息功能的实现原理相类似。首先需要创建一个数据文件用于储存用户的订单信息(用户执行预订航班的操作后将产生对应订单)。订单信息数据格式示例如下:
但预订航班与添加航班信息不同的地方在于,用户首先需要根据自己的需求搜索对应的航班,然后从系统展示出的符合条件的航班中选择符合需求的一个航班,通过验证后才会生成对应的订单信息并将其追加在订单信息文件的末尾。结合实际情况,本系统设计为可以通过两种方式预订航班,一种是指定起点城市搜索航班,另一种是指定终点城市搜索航班。*由于本系统使用的数据库量较小所以只用这两种方式就可以满足搜索需求,若使用较大的数据库则需要编写同时指定起点和终点城市的搜索功能。用户指定城市名称后,系统会在航班信息顺序表中查找匹配的航班信息,然后将结果输出在屏幕上供用户参考选择。验证函数存在的意义是,对于预订航班这个功能来说,用户执行该操作后可能会产生多种情形,例如:用户成功预订该航班;用户已经预订过该航班(不可重复预订);该航班已经满座等等。而这些情形又都是不可忽略的,如果忽略了哪怕只有其中一种,也可能会产生严重的逻辑错误。因此验证函数必不可少。以下为验证函数的主要代码:
if(select_num==0){//若用户输入0则返回主界面fg=-4;return fg;}for(k=0;kif_full=='Y'){fg=-1;break;}else{printf("┌----------------------------------┐\n");printf("├ 是否确认预订该航班? ┤\n");printf("├----------------------------------┤\n");printf("├ 选择操作: ┤\n");printf("├ 1.确认2.取消并选择其他航班 ┤\n");printf("├ 3.我不想预订航班了,返回主界面 ┤\n");printf("└----------------------------------┘\n");getchar();switch(getchar()){case '1':printf("请输入您的证件号验证身份:");scanf("%s",u_id_num);if(strcmp(u_id_num,user[un].id_num)==0){order_info_append(user[un].username,select_num);order_num++;fg=1;return fg;//用户成功预订}else{fg=-2;//证件号输入错误return fg;}case '2':fg=-3;//用户选择其他航班break;default:fg=-4;//用户取消了订单return fg;}}}}return fg;
运行示例:
原始订单数据
预订航班时可能出现的问题
订单信息已追加
退订航班的功能与删除航班信息的原理一致,在此不再赘述。
小结
以上便是关于C语言课程设计——航班信息管理系统的全部内容。由于笔者水平有限,若相关知识点出现错误,或对内容有疑问,欢迎在评论区留言。需要程序源码及1.5w+字的设计报告也可以私信我。最后,感谢您的阅读,如果本文对您有帮助,希望能留下个小小的赞。