您的当前位置:首页正文

C语言版--火车站售票系统报告及代码解析

2021-06-11 来源:榕意旅游网


《C语言大作业》设计说明书

--- 火车站售票系统

学 号: 08030337 姓 名: 朱陈立 班 级: 08软件 指导教师: 曹中心

2008年6月23日-- 6 月27日

目录

第一章——————————————课程认识 第二章——————————————课题选择 第三章———————————总体设计与分析 第四章————————————模块详细设计 第五章————————————主要实现方法 第六章————————————课程设计总结 第七章————————————————结论 第八章————————————————建议

一、课程的性质、任务、目的

C语言是非常优秀的程序设计语言,应用广泛,是高校计算机专业的一门专业基础课程;学好C语言,是学习计算机专业课程和用好计算机的重要基础。要学好C语言,应抓好理论学习、上机实验以及综合应用这三个环节。

在《C程序设计》课程的学习中,学生在掌握C语言理论知识的同时,通过上机实验完成一定量的实践性题目,初步掌握了程序设计的基本思想、基本概念和基本方法。本课程是计算机专业的学生在完成了《C程序设计》课程的学习后,为加强学生对程序设计思想的理解、通过解决有一定代表性的小型综合应用类课题从而提高实际编程能力而设置的一门实践性课程。

本课程为学生提供了一个既动手又动脑,独立实践的机会,将课本上的理论知识和实际有机地结合起来,培养和锻炼学生分工协作、分析和解决实际问题并利用计算机求解问题的能力,以提高学生适应实际,实践编程的能力,从而掌握基本的程序设计过程和技巧,具备初步的高级语言程序设计和调试能力。

二、课题选择(背景、意义、实用性……);

背景:现今,人们的生活水平渐渐改善,生活质量也随之提高,人们的精神需求也大了,应此,出行旅游,或是走访亲友成了习以为常的事了,出行已成为现代人的家常便饭,汽车,火车,飞机等交通工具为我们提供了更多的方便。然而在售票中,就需要一个售票系统来帮助售票员来更为快捷,高效,方便的售票,同时也为了车站方面更好的管理票务,因此,一个好的车票管理系统就必不可少了。

意义:选择车站售票系统作为课程设计的课题,就车站的售票流程等进一步了解车站的售票系统的原理。在编程过程中能力培养我们团结协作和项目管理能力:设计任务分配和模块划分、参考资料共享、系统基本信息的建立与共享、作业中技术难题的讨论与实验、系统的联合调试、文档资料的建立与维护。自学能力和文献查阅能力项目开发基本流程理解、规划和实施。程序调试能力:程序开发中常用的单步调试、断点设置、中间结果输出等。项目测试能力:掌握基本的测试要素,能完成单体测试和综合测试过程。良好的编程风格:代码缩进书写,合理划分子程序,为程序添加必要的注释以方便程序阅读和维护,采用菜单、图形或各种提示说明方便用户使用程序。

实用性:火车站售票系统。随着列车的再次提速,车次也明显增加,新开路线增多,因此票务也变得越来越复杂,而一个便捷,高效的票务管理系统就必不可少了。

三、总体设计与分析(总体框架图及简要功能说明);

就我们的程序来说,总体框架图

如下:

火车站售票系统 管理员 售票员 退出系统 添加 新增列车信息 修改列车信息 删除已无列车信息 修改管理员密码 售票 换票 退票 修改售票员密码 退出

上图就是简易的结构图,先制作一个主菜单,进入售票系统的主页面,上面的出现选择菜单,可以根据你输入的字符来选择进入那个部分,分别为管理员与售票员两种,另外,不管是管理员还是售票员,都有一个退出的选择,对于现实生活中的情况,由于在操作时的随意性很大,退出选项并不是退出系统,而是退回到主菜单,则又可以进行选择输入,也可以从管理跳到售票员,而这样就具有人性化了,在管理员修改资料库后必须要检查,所以就要进入售票系统,检查票务是否已经修改或删除完成,在主菜单中可以自由选择。

在售票员的系统中又分类进行,划分了五个模块,有售票,换票,还有退票,最后一个就是退出了,可以退到主菜单,在售票中每次都会可以退到售票员。

四、模块详细设计(流程图+说明+承担任务);

售票员的总体框架图如下:

选择1 选择2 售票员 选择3 选择4 选择5 售票 换票 退票 修 改密码 退出 主菜单 说明:售票员的程序中也包括了五个部分,分为售票,退票,换票和修改密码以及退出操作,前面的四个部分是基本操作,能够对原文件进行操作的程序,同样是退到主菜单的操作,每次基本操作玩了之后,又会自动转到售票员的主页面去,而退出和以上的管理员的是一样的,自动退到主菜单。

下面主要介绍的是售票员的部分。

五、主要实现方法(结构体、文件、函数、指针、主要程序段……);

程序中用到的结构体如下: struct trian {

char name[10]; char qs[20]; char zd[20]; char date[20]; char time1[20]; char time2[20]; int price; int num;

} tri[N],ticket[N];

说明:在结构体中tri[N],ticket[N];由于一组两个人的分工不一样,所以在编程时

由于喜好不一样就用了两个不一样的结构体变量,在拼凑时,由于用到的地方很多,难以逐个修改,应此就在定义结构体变量时,引用了两个不一样的变量,不过他们承载的功能是一样的,只是形式不一样而已。再来观察结构体,在结构体中定义了出发地,目的地,日期,出发时刻,到达时刻,还有价格,另外,为了高效便捷的记录下票的张数,以及座位号码,而座位号码又是根据票的张数来排的,这样有减少了计算机的工作量又简捷。

文件: D:\\\\票.txt D:\\\\密码.txt D:\\\\secret.txt

说明:在程序运行中总共会用得到以上三个文件,第一个是要调用的票务文件,里面总共包括了所有的票务信息,无论是在管理员还是售票员的程序里,自始至终都要用到这个文件,在管理员中,有对列车信息的修改,删除和新增,这些的变化都得在写进总的票务文件,要覆盖掉原来的文件,以保证售票员的买票有效正常。在售票员的程序里,一直是用的票务文件,由于售票员的业务会比较多,差不多票务文件每时每刻都在被修改,所以每次修改后都要被保存到该文件中。 “密码”文件:该文件用于存放管理员的密码,在第一次运行中程序时必须要先初始化一个密码,这样才能进入管理员的界面,在才能进入票务文件。在密码的修改中每次修改密码后都必须把新的密码写入密码文件,否则在下次打开时还是原始的密码,而修改的并不能成功。详细见后面程序说明,简言之,就是存放管理员的的密码的文件。

“secret”文件:该文见与密码文件是差不多的,它是用看来保存售票员的密码的,在程序初始化的时候也必须写入一个初始化的密码,在使用过程中如果要修改密码,则该文件就是用来保存密码的,当要换新的密码时,由于在后面程序中有相关操作,会自动将要换的密码写进secret文件,并自动将原文件覆盖掉, 从而再次进入 售票员的界面时则要输入的密码会修改成功,原来的密码就不能在用了,会有系统提示“密码输入有误! ”。

主要函数:

(1)main函数:

void main() {

output(); int n,t=0; while (t==0) { printf(\"************************************************\\n\");

车站售票系统

printf(\"**********************请选择用户类型***********************\\n1管理员 2售票员 3退出\\n\"); scanf(\"%d\ system(\"cls\"); switch(n) { case 1: guanliyuan();break; case 2: shoupiaoyuan();break; case 3: t=1;break; default: printf(\"输入错误!!!\\n\"); } } }

说明: main函数,主要是编辑了主菜单,有三个选择,会出现选择来让使用人进入那个部分,有管理员和售票员两个,还有一个退出选项,使用了switch语句进行操作,先假定一个变量t,因为存在输入错误的可能,只有当预设条件不成立时才会跳出循环,所以假设t初始值为0,只有当条件成立时才能继续执行,即t=0时;当输入错误的时候,则将t的值重新赋值给1,则引起条件改变,跳出循环。因此,一个主菜单就完成了。

(2)shoupiaoyuan函数

void shoupiaoyuan() {

char key[128],key1[128],id1[128],id[128]=\"2\"; FILE *fp;

/* fp=fopen(\"D:\\\\secret.txt\第一次输入售票员密码,并将密码写进文 if(fp==NULL) 文件 { printf(\"Open Error!\\n\"); return; }

char s[128]=\"2\"; fprintf(fp,\"%s\ fclose(fp);

*////////////即初始化密码,也可用于一键还原。 fp=fopen(\"D: \\\\secret.txt\ if(fp==NULL) { printf(\"Open Error!\\n\"); return; }

fscanf(fp,\"%s\ int flag=1; int n,i=0;

printf(\"\\\*********售票员*********\\n\"); printf(\"请输入工号:\"); scanf(\"%s\

printf(\"请输入密码:\");

while(1)//////////////////////////////////密码出入处理,出入字符,输出“*”号 { key1[i]=getch(); if(key1[i]==13) break; putchar('*'); i++; }

key1[i]='\\0'; printf(\"\\n\");

system(\"cls\");/////////////////////////////输入密码清屏一次 if (strcmp(id1,id)==0&&strcmp(key1,key)==0) { printf(\"\\\***********welcome*********\\n\"); while(flag==1)/////////// flag标记,用于实现循环 { printf(\"请选择操作:\\n1售票\\n2换票\\n3退票\\n4修改工作密码\\n5退出\\n\"); scanf(\"%d\ switch(n) { case 1: sell();break; case 2: change();break; case 3: back();break; case 4: secret();break; case 5: flag=0;break; default:printf(\"输入错误,请重新输入!\\n\"); } } } else printf(\"登陆错误,前重新输入!\\n\"); system(\"cls\"); fclose(fp); }

说明:在第一个被取消掉的部分就是密码的初始化程序,同时也用了switch函数,进行了函数选择运行的工作,下一部分中,从secret的文件中读出原始密码,在提示语后输入字符后就进行与原密码的比对,如果相符就可以进如下一步操作,不相符的话就输出“登陆错误,请重新输入!”,在售票员的主界面中也有选择操作,再次运用了switch语句,就不做过多的介绍了。 (3)sell函数-----售票函数 void sell() {

time_t now;

now=time(NULL);

char s1[128],s2[128],s3[128],s4[128]; char a; FILE *fp;

int i,len,t,n,m=1;

fp=fopen(\"D: \\\\票.txt\ if(fp==NULL) { printf(\"Open Error!\\n\"); return; }

for(i=0;!feof(fp);i++) ////////读取文件信息,逐条读出,当没有时结束 fread(&ticket[i],sizeof(struct trian),1,fp); len=i-1;

printf(\"请输入出发地(全拼):\"); scanf(\"%s\

printf(\"请输入目的地(全拼):\"); scanf(\"%s\

for(i=0;i{printf(\"%-10s %-10s %-10s %-10s %-10s %-10s %3d\\n\qs,ticket[i].zd,ticket[i].date,ticket[i].time1,ticket[i].time2,ticket[i].price); //// /// m=0; 定义一个m,作为标记,用来判断输入的字符串在

} 文件中是否能够找得到,只要能够找的到,就让m

} 等于0(上面定义里m=1),到下面if里面只要m

if(m!=0) 不为0,就说明没找到,否则,就是输入正确的,则 { 继续,m继续赋值为1,用于下一个部分输入的判 printf(\"输入错误!\\n\"); 断 printf(\"按任意键继续................\"); a=getche(); system(\"cls\"); ////////////当输入错误时,要重新输入,则清屏一次 return; }m=1;

printf(\"请输入所需票的日期:\"); scanf(\"%s\ for(i=0;iif(strcmp(ticket[i].qs,s1)==0&&strcmp(ticket[i].zd,s2)==0&&strcmp(ticket[i].date,s3)==0)

{printf(\"%-10s %-10s %-10s %-10s %-10s %-10s %3d\\n\qs,ticket[i].zd,ticket[i].date,ticket[i].time1,ticket[i].time2,ticket[i].price); m=0;} 上一次的判断结束后,m又赋值了给1 }

if(m!=0) ////////////// 同上的判断一样,利用了变量m值得的变化 { printf(\"输入错误!\\n\"); printf(\"按任意键继续................\"); a=getche(); return;

} m=1;

printf(\"请输入车次:\"); scanf(\"%s\ printf(\"请输入买的票的张数:\"); scanf(\"%d\ for(i=0;iif(strcmp(ticket[i].qs,s1)==0&&strcmp(ticket[i].zd,s2)==0&&strcmp(ticket[i].date,s3)==0&&strcmp(ticket[i].name,s4)==0) { ///////买票成功了,则文件中的票的数据要更改, ticket[i].num=ticket[i].num-n; 票的张数要减去卖出的张数,程序结束 t=i; 时将剩余张数再次写进文件 m=0; } }

if(strcmp(ticket[t].name,s4)!=0) { ///////////// 每输入一次就判断输入的是否正确,以提高效率 printf(\"输入错误!\\n\"); printf(\"按任意键继续................\"); a=getche(); return; }

for(i=0;iprintf(\"%-10s %-10s %-10s %-10s %-10s %-10s %3d %3d\\n\et[t].qs,ticket[t].zd,ticket[t].date,ticket[t].time1,ticket[t].time2,ticket[t].price,ticket[t].num+n-i);

///该条语句为将票有打印机打印出来的顺序,最后将座位号,时间也打印在票上 printf(\"%s\\n\ }

printf(\"该票剩余数:%2d\\n\ if(ticket[t].num<0) printf(\"无票! \\n\"); ////////////如果读出的剩下的票的张数小于0 时,则输 else 出无票 printf(\"恭喜,购票成功! \\n\"); printf(\"按任意键继续................\"); a=getche();

system(\"cls\");/////////////////////////售完一次票清屏一次 fclose(fp);

fp=fopen(\"D: \\\\票.txt\ for(i=0;i说明:首先,打开票务文件,在进入买票的界面后,可以输入出发地和目的地,输入后则判断一次,看在文件中是否能够找的到,在判断中用m变量来实现,

具体见程序旁说明,如果过输入不正确则重新输入,输入正确则继续输入下一条字符串,当输入的全部正确的话则将此票在文件中的num减去售出的张数,在打出票时,用循环来实现,座位号要按顺序排下去,则用ticket[t].num+n-i实现,先还原到原始票的张数,在由于i是从0 开始增加的,就加上i,则可以 打出座位号了,买了几张就打几张票出来,在打出的票上标有出发地,目的地,日期,出发时刻,到达时刻,票价,时间和座位号。

(4)back函数-------退票函数

void back() {

char s1[128],s2[128],s3[128],s4[128];char a;int i,len,t,n,m=1;double money; FILE *fp; ////////////////售票员的操作,都是对文件的操作,应此每次都要 fp=fopen(\"D: \\\\票.txt\ 先打开文件 if(fp==NULL) { printf(\"Open Error!\\n\"); return; }

for(i=0;!feof(fp);i++) fread(&ticket[i],sizeof(struct trian),1,fp); len=i-1;

printf(\"请输入要退的票的出发地(全拼):\"); scanf(\"%s\

printf(\"请输入要退的票的目的地(全拼):\"); scanf(\"%s\ for(i=0;iif(m!=0) ////////////同样对输入的字符串在文件中查找判断。用m { 来标记 printf(\"输入错误!\\n\"); printf(\"按任意键继续................\"); a=getche(); system(\"cls\"); return; } m=1;

printf(\"请输入所退的票的日期:\"); scanf(\"%s\ for(i=0;iif(strcmp(ticket[i].qs,s1)==0&&strcmp(ticket[i].zd,s2)==0&&strcmp(ticket[i].date,s3)==0) m=0; }

if(m!=0) ////////////同样对输入的字符串再次在文件中更精确地查找判断。用m

{ 来标记 printf(\"输入错误!\\n\"); printf(\"按任意键继续................\"); a=getche(); system(\"cls\"); return; } m=1;

printf(\"请输入车次:\"); scanf(\"%s\ for(i=0;iif(strcmp(ticket[i].qs,s1)==0&&strcmp(ticket[i].zd,s2)==0&&strcmp(ticket[i].date,s3)==0&&strcmp(ticket[i].name,s4)==0) m=0; }

if(m!=0)/////// 同样用m来标记,实现下面的判断功能 { printf(\"输入错误!\\n\"); printf(\"按任意键继续................\"); a=getche(); system(\"cls\"); return; } m=1;

printf(\"请输入退的票的张数:\"); scanf(\"%d\ for(i=0;iif(strcmp(ticket[i].qs,s1)==0&&strcmp(ticket[i].zd,s2)==0&&strcmp(ticket[i].date,s3)==0&&strcmp(ticket[i].name,s4)==0) { ticket[i].num=ticket[i].num+n;//printf(\"%d\ t=i; money=ticket[t].price*0.8; ////// 由于存在乘以80%,所 printf(\"请返回顾客 %f 元\\n\ 以票价要定义double型 m=0; } }

if(m!=0) ///////////////////同样用m来标记,实现下面的判断功能 { printf(\"输入错误!\\n\"); printf(\"按任意键继续................\"); a=getche(); system(\"cls\"); return; }

m=1;///////////////////////m重新赋值给1用于下一次的判断

}

fclose(fp);

fp=fopen(\"D: \\\\票.txt\再次打开文件对已改变的文件进行保存 for(i=0;ifclose(fp);

printf(\"退票成功!\\n按任意键继续................\"); a=getche();

system(\"cls\"); ///////////清屏一次自动退出退票系统,进入售票员主界面

(5)change函数-----换票函数

换票函数:即为售票函数与退票函数的集合,换票就是先退票在买票,具体请看sell函数和back函数。

(6)secret函数-----修改密码函数

void secret() {

system(\"cls\");///////// 进入密码修改清屏一下,直接出现输入提示语 char a ; FILE *fp3;

fp3=fopen(\"D: \\\\secret.txt\ /////////////先读取存放原密码的文件 if(fp3==NULL) /////////正常打开 { printf(\"Open Error!\\n\"); return; }

char key[128],key1[128],newpass1[128],newpass2[128]; fscanf(fp3,\"%s\ fclose(fp3);

printf(\"请输入原始密码:\"); int i=0; while(1) //////////////实现输入字符而输出“*”号 { key1[i]=getch(); if(key1[i]==13) break; putchar('*'); i++; }

key1[i]='\\0'; printf(\"\\n\");

if(strcmp(key1,key)==0) { do//////////////一直运行至至条件不符合 { printf(\"请输入新密码:\");//////第一次输入密码 i=0;

while(1) { ////// ////// 实现“*”号输出,不显示字符以提 newpass1[i]=getch(); 高安全性 if(newpass1[i]==13) break; putchar('*'); i++; } newpass1[i]='\\0'; printf(\"\\n\"); printf(\"请再次输入新密码:\");///////第二次输入密码 i=0; while(1) { newpass2[i]=getch(); if(newpass2[i]==13) break; putchar('*'); i++; } newpass2[i]='\\0'; printf(\"\\n\"); if(strcmp(newpass1,newpass2)!=0)/

两次的进行比较,如果两次的不一样,则不能正确修改,也不知道是第一次还是第二次输入错误,则可以重新输入 { printf(\"两次不符,请重新更改:\"); printf(\"按任意键继续................\"); a=getche(); system(\"cls\"); } }while(strcmp(newpass1,newpass2)!=0);////////只有当两次输入完全一 printf(\"恭喜,密码修改成功!\\n\"); 样系统才会自动覆盖 printf(\"按任意键继续................\"); 原始secret文件 a=getche(); system(\"cls\"); fclose(fp3); fp3=fopen(\"D: \\\\secret.txt\将新改的密码写入secret文件 fprintf(fp3,\"%s\ fclose(fp3); } else printf(\"密码错误!\\n\"); }

说明:在密码修改程序中,需要先输入的密码与原密码,如果正确了才能进入修改程序,才会出现修改提示,你的新密码必须连续输入两次,且两次都必须一样才能修改成功,而不管是第一次输入有误还是第二次有误,修改成功的密码会被写入secret文件被保存,用于下一次的登录,下次登录时用的就是新密码了。

六、课程设计总结(问题及解决、实现情况、评价、存在问题及改进思路);

问题及解决:

在开始时写售票程序的时候,首先并没又想到座位号的问题,因此在优化的过程中有增加了座位号的输出,巧妙地利用了票的剩余张数来作为座位号。 在开始时从机房拷回家后总是不能运行,后来发现是文件打开的途径不对,经过几次的教训,就把途径不变,把票文件,密码文件,secret文件写到了D盘根目录里去,省去了很多不必要的工作量。

在修改密码时老是不能把新密码写入文件,结果改过来还是不能运行,经过仔细的查看程序发现了问题,最终增加了写入文件。

还有在写程序的过程中,每次都会遇到打开文件,则我们会用复制粘贴,而忘记了更改读或写的方式,因此在每次复制粘贴之后必须看一下有没有要更改的,有的话一定要及时更改过来,不然到最后程序大了,则会增加工作量。

实现情况:

在函数的实现过程中,没有遇到很多的问题,只是屏幕上显示的语句太多,因此学会了用清屏语句,system(“cls”)语句,在每次的一个操作结束后,则可以清一次屏,是界面看起来更加的简洁明了。另外,在刚开始在主函数中无法实现功能的选择,通过讲解,学会了使用switch语句来将调用函数连接在一起。

评价:

基本上用到了我们所学的所有知识,在大作业的过程中,翻过好几次书,书上的 很多知识都用到了,还有在大作业中团结协作是很重要的,

存在问题及改进思路:

存在问题:首先是我们的页面不整齐,不美观,感觉输出的东西杂乱,不具美观性,

其次就是考虑问题还不全面,有很多在管理方面可能出现的问题没考虑到。如:管理员售票员的密码修改,票的,按时上班,奖金张数,无票的提醒,如何进行必要的清屏等等。

改进思路:在设计时要先规划,多花点时间规划,

以及在调用函数时,将所有情况考虑进去,做到更加完善。

七.结论(课程设计心得);

C语言大作业是团体合作共同完成的一项任务,合作者之间的交流很重要,如果编程者只是为了完成自己的任务而独自编写,各模块进行整合的时候,可能会出现相当大的差异,而且编程者可能出于坚持各自的想法,而使任务在规定时间内无法完成。

在平时学习C语言时,注意知识的全面性,C语言大作业所需的知识相当全面,所以平时的积累也是相当重要的。

在团体编写程序过程中,我们自身也应具备相当多的素质:我们肯下功夫,有恒

心,有毅力的精神,在完成C语言的过程中往往有的错误不是一眼就能看出来的,我们要善于思考,而且思考的要尽量全面。第一,我们要完成自己所需要完成的模块,在完成过程可能会出现很多麻烦的错误,在自己努力修改后还是没能修改出来时,我们应积极讨论,不应放弃,询问合作者,如果两人都无法修改的话,就想老师求助。在模块整合时,往往会出现相当多的问题,每个人有每个人的设计理念,可能想法上会发生分歧,这时我们应冷静的交流,取最佳的想法,实现模块的成功整合。可能同一组的成员之间编写C语言的能力有差异,优秀的人在完成自己任务后也应辅导帮助其他人完成他们的任务,C语言大作业,完成的好坏不是靠个人的力量,是集体。而且在评价C语言大作业时,也不是拿出个人的模块来评价,也是直接评价这个组队完成的情况。

八.建议;

一、C语言大作业是一项有助于我们整合所学知识以及培养我们编写程序能力的工作,编程虽然辛苦,但是学到东西很多,它将我们所学知识成功运用到生活中去,也有利于我们组员之间的合作能力,将编程方式应与我们平时教学联系在一起,在老师的指导下,提供我们更多这样的机会。

二、可以拓展我们的知识层面,将我们C语言编写的功能进一步深入,可能我们知识有限,不能成功完成任务,我们可以通过自己看书以及求助同学来完成任务。 三、讲解一些实用性的程序,如(密码的设定,清屏,获取时间日期等),拓展我们关于实用性语言方面的知识,能在编写一些关于生活方面的应用型程序时,我们有足够的知识来完成。

因篇幅问题不能全部显示,请点此查看更多更全内容