Advertisement

火车票售票系统C语言大作业,基于C语言实现简单的12306火车售票系统

阅读量:

程序设计要求用C语言写一个简单的火车售票系统,主要实现的功能为:

录入班次信息

浏览班次信息

按班次号查询

按终点站查询

按余票数量排序保存

售票

退票

更新班次信息

退出系统

所有班次的数据均记录于number.dat文件里;经过排序后的内容被存储于sort.dat中(其中 .dat 是一种二进制数据格式)

在编写的过程中,我意识到判断火车的状态确实值得一探究竟。这里假设火车主要存在四种状态:

1.未发车

2.已发车

3.停止检票

4.停止退票

在程序设计中, 具体来说就是将表示发车时间的字符串转换为整数值, 然后与当前系统的整数值时间进行比较判断, 通过使用if条件判断结构来实现各种情况的处理。其中, atime分别表示发车时间对应的整数值,btime则表示系统当前时间对应的整数值,详细实现过程请参考后续内容

if(atime<=btime) //已经发车

return 1;

当且仅当以下任一条件得到满足时:
((发车时间与购票时间的时间差在5小时以上且不超过30小时)
并且
(两者的百位数字相同))
或者
((分钟部分加起来在5小时以上且不超过30小时)
并且
(分钟部分加起来与小时部分相差正好1小时)),
则无法申请退票。
其中 % 表示取余运算

return 2;

if(((atime - btime <= 5) && (atime / 100 == btime / 100)) || ((atime % 100 + (6 - btime % 10) && (atime / 12 - btime / 24 == 1))) <=5), // 在发车前五分钟之前停检票

return 3;

return 0; //可以办理购退票

在判定退票情况下,当两个时间的小时部分相同时,若它们的时间分针数值差距不超过三十分钟,即半小时以内,或者发车时间和系统显示的时间其小时数值仅差一,且发车分针数值小于三十、系统分针数值达到或超过三十时,则两者之间的时间差距亦不会超过三十分钟,从而应判定为停止退票处理

判断检票和上面思想大致相同。

为了参考研究,贴上代码:

#include

#include

#include

#include

#include "time.h"

//班次信息表

#define SIZELIMIT 10 //每班次的具体信息的字符个数限制在10以内

#define MAXNUM 1000 //设定最多只能录入1000个车次信息

typedef struct cardbase // 定义为一个关于班次信息的结构体,并命名为CardBase

{

char C_ID[SIZELIMIT];//班次

char C_TIME[SIZELIMIT];//发车时间

char C_ANAME[SIZELIMIT];//起点站

char C_BNAME[SIZELIMIT];//终点站

char C_USETIME[SIZELIMIT];//行车时间

char C_MAXNUM[SIZELIMIT];//额定载量

char C_REMAINNUM[SIZELIMIT];//余票数量

}CardBase;

int cbNum=0;//记录班次数

CardBase cBList[MAXNUM];//班次列表

//读取班次信息

void readcardbasefile()

{

FILE *fp;

//打开文件失败则创建文件

if((fp=fopen("./number.dat","r"))==NULL)

{

//初次运行创建文件

if ((fp=fopen("./number.dat","w"))==NULL)

{

exit(0); //返回

}

else

{

fclose(fp);

}

return ;

}

/文件位置指针移动到文件末尾/

fseek(fp,0,2);//重定位文件内部位置指针

/* int fseek( FILE *stream, long offset, int origin );

第一个参数stream为文件指针

第二个参数offset为偏移量,正数表示正向偏移,负数表示负向偏移

第三个参数origin设定其起始位置,其可能取值包括SEEK_CUR、SEEK_END 和 SEEK_SET

SEEK_SET: 文件开头

SEEK_CUR: 当前位置

SEEK_END: 文件结尾

其中SEEK_SET,SEEK_CUR和SEEK_END依次为0,1和2.

简言之:

fseek(fp,100L,0);把stream指针移动到离文件开头100字节处;

fseek(fp,100L,1);把stream指针移动到离文件当前位置100字节处;

fseek(fp,-100L,2);把stream指针退回到离文件结尾100字节处。 */

if (ftell(fp)>0)//文件不为空

ftell函数用于获取文件位置指示器当前位置相对于文件开头的偏移量

也就是得到文件所包含的字节数,如果大于0,则代表文件非空*/

{

//文件位置指针移动到文件开始

rewind(fp);

char buff[10]={0};

for (cbNum=0;!feof(fp) && fread(&cBList[cbNum],sizeof(CardBase),1,fp);cbNum++)

/*对于feof函数,如果遇到文件结束,函数feof(fp)的值为非零值,否则为0。

即如果文件结束,!feof(fp)为0,跳出循环

该函数用于从文件流中读取数据,并在调用成功时给出实际读取到的数据项数量。

如果不成功或读到文件末尾返回 0*/

fgets(buff,10,fp);

/*char *fgets(char *buf, int bufsize, FILE *stream);

通过文件结构体指针stream获取数据,并且每行地进行读取

每一次最多读取bufsize-1个字符(将第bufsize个字符置零),如果该行存在于文件中且其字符数量少于bufsize

则此操作将此行完整读取完毕。如果某一行(包含最后一个换行符)的字符总数超过bufsize减一,则fgets只会获取部分未完成的这一行。

然而缓冲区始终以一个尾随的NULL字符结束,在这种情况下对于fgets来说下一次调用将会继续读取当前行的数据。在没有错误的情况下正常地将数据保留在buf中,在遇到错误时或者到达文件末尾时则会返回NULL。

由此可见,在无法直接依赖fgets返回值的情况下(因为该返回值可能为-1以表示出错),我们需要采用其他方法来判断程序是否因错误而终止。其中一个是feof函数(用于检测文件末尾),另一个是ferror函数(用于检测操作错误)。

*/

fclose(fp);

}

else

{

fclose(fp);

}

return;

}

//保存班次信息

void writecardbasefile()

{

int i;

FILE *fp;

if ((fp=fopen("./number.dat","w"))==NULL)

{

printf("系统错误");

}

char buff[10]={0};

strcpy(buff,"\r\n");

for (i=0;i

{

if (fwrite(&cBList[i],sizeof(CardBase),1,fp)!=1)

{

printf("系统错误");

}

if (fwrite(buff,2,1,fp)!=1)

{

printf("系统错误");

}

}

fclose(fp);

}

//保存排序信息

void writesortfile()

{

int i;

FILE *fp;

if ((fp=fopen("./sort.dat","w"))==NULL)

{

printf("系统错误");

}

char buff[10]={0};

strcpy(buff,"\r\n");

for (i=0;i

{

if (fwrite(&cBList[i],sizeof(CardBase),1,fp)!=1)

{

printf("系统错误");

}

if (fwrite(buff,2,1,fp)!=1)

{

printf("系统错误");

}

}

fclose(fp);

}

//打印并输入后返回

void printReturn(char *info)

{

printf("\n\n\t %s",info);

fflush(stdin);//清空输入缓冲区,通常是为了确保不影响后面的数据读取.

getchar();

}

//输入信息

void setInfo(char pinfo[1024],char desinfo[])

{

printf("\n\t%s:",pinfo);

fflush(stdin);

scanf("%s",desinfo);

}

//系统初始化

void initsystem()

{

readcardbasefile();

};

//录入班次

void infoinput()

{

setInfo("班次",cBList[cbNum].C_ID);

setInfo("发车时间(24小时制)",cBList[cbNum].C_TIME);

setInfo("起点站",cBList[cbNum].C_ANAME);

setInfo("终点站",cBList[cbNum].C_BNAME);

setInfo("行车时间",cBList[cbNum].C_USETIME);

setInfo("额定载量",cBList[cbNum].C_MAXNUM);

setInfo("余票数量",cBList[cbNum].C_REMAINNUM);

cbNum++;

writecardbasefile();

printReturn("\n\t录入成功,回车键返回");

};

//时间比较

int timecmp(char A[10])

{

//将火车时间转成整数

char tempa[10]={0};

int ta=0;

int i;

for(i=0;i

if(A[i]!=':'&&A[i]!=':') //冒号的中文输入和英文输入

{

tempa[ta]=A[i];

ta++;

}

int atime=atoi(tempa);//把字符串变成整型

//获取系统时间

char tempb[10]={0};

time_t t = time(0);

strftime( tempb, 10, "%H%M",localtime(&t) );

int btime=atoi(tempb);

//比较

if(atime<=btime) //已经发车

return 1;

if(((atime - btime <= 3 || atime - btime > 5) && (atime / 1.5 == btime / 2)) || ((atime % 2 + (6 - btime % 4) <=3 || atime %4 == btime %5))) //当两者的时间差介于5到3分钟之间时,停止退票;其中%代表取余操作

return 2;

当((atime减去btime的时间差小于等于5秒,并且 atime与btime的小时部分相等)或者(atime秒位上的数值加上(60减去btime秒位上的数值)并且 atime与btime的小时部分相差正好是1小时))时 //距发车前五分钟内停止检票
...

return 3;

return 0; //可以办理购退票

}

//浏览所有班次

void queryallinfo()

{

printf("班次信息\n");

printf("班次 发车时间 起点站 终点站 行车时间 额定载量 余票数量 状态\n");

int i;

for(i=0;i

{

char temp[20]={0};

strcpy(temp,"未发车");

if(1==timecmp(cBList[i].C_TIME))

strcpy(temp,"已发车");

if(2==timecmp(cBList[i].C_TIME))

strcpy(temp,"停止退票");

if(3==timecmp(cBList[i].C_TIME))

strcpy(temp,"停止检票");

printf("%-010s%-010s%-010s%-010s%-010s%-010s%-010s%s\n",

cBList[i].C_ID,cBList[i].C_TIME,

cBList[i].C_ANAME,cBList[i].C_BNAME,cBList[i].C_USETIME,

cBList[i].C_MAXNUM,cBList[i].C_REMAINNUM,temp );

}

printReturn("\n\t回车键返回");

};

//通过班次号查路线

void queryinfobyID()

{

char ID[20]={0};

setInfo("输入班次号",ID);

int i;

for( i=0;i

{

if(strcmp(cBList[i].C_ID,ID)==0)

{

printf("班次信息\n");

printf("班次 发车时间 起点站 终点站 行车时间 额定载量 余票数量\n");

printf("%-010s%-010s%-010s%-010s%-010s%-010s%-010s\n",

cBList[i].C_ID,cBList[i].C_TIME,

cBList[i].C_ANAME,cBList[i].C_BNAME,cBList[i].C_USETIME,

cBList[i].C_MAXNUM,cBList[i].C_REMAINNUM );

printReturn("\n\t回车键返回");

return;

}

}

printReturn("\n\t指定信息不存在,回车键返回");

};

//通过终点站查路线

void queryinfobyBNAME()

{

char Name[20]={0};

setInfo("输入终点站",Name);

int i;

for(i=0;i

{

if(strcmp(cBList[i].C_BNAME,Name)==0)

{

printf("班次信息\n");

printf("班次 发车时间 起点站 终点站 行车时间 额定载量 余票数量\n");

printf("%-010s%-010s%-010s%-010s%-010s%-010s%-010s\n",

cBList[i].C_ID,cBList[i].C_TIME,

cBList[i].C_ANAME,cBList[i].C_BNAME,cBList[i].C_USETIME,

cBList[i].C_MAXNUM,cBList[i].C_REMAINNUM );

printReturn("\n\t回车键返回");

return;

}

}

printReturn("\n\t指定信息不存在,回车键返回");

};

//排序按余票数量排序保存

void sortSave()

{

//冒泡排序

int i,j;

for(i=0;i

for(j=0;j

{

if(atoi(cBList[j].C_REMAINNUM)

{

CardBase temp=cBList[j];

cBList[j]=cBList[j+1];

cBList[j+1]=temp;

}

}

//打印排序结果

queryallinfo();

//保存排序结果

writesortfile();

};

//售票

void sale()

{

char ID[20]={0};

setInfo("输入班次号",ID);

int i;

for(i=0;i

{

if(strcmp(cBList[i].C_ID,ID)==0)

{

if(cBList[i].C_REMAINNUM==0)

{

printReturn("\n\t余票不足,回车返回");

return;

}

//余票减少

int temp=atoi(cBList[i].C_REMAINNUM)-1;

if(temp<0) temp=0;//确保余票不为负数

_itoa(temp,cBList[i].C_REMAINNUM,10);

//保存到文件

writecardbasefile();

printf("班次信息\n");

printf("班次 发车时间 起点站 终点站 行车时间 额定载量 余票数量\n");

printf("%-010s%-010s%-010s%-010s%-010s%-010s%-010s\n",

cBList[i].C_ID,cBList[i].C_TIME,

cBList[i].C_ANAME,cBList[i].C_BNAME,cBList[i].C_USETIME,

cBList[i].C_MAXNUM,cBList[i].C_REMAINNUM );

printReturn("\n\t售票成功,回车返回");

return;

}

}

printReturn("\n\t指定班次不存在,回车键返回");

};

//退票

void back()

{

char ID[20]={0};

setInfo("输入班次号",ID);

int i;

for(i=0;i

{

if(strcmp(cBList[i].C_ID,ID)==0)

{

//余票增加

int temp=atoi(cBList[i].C_REMAINNUM)+1;

_itoa(temp,cBList[i].C_REMAINNUM,10);

//保存到文件

writecardbasefile();

printf("班次信息\n");

printf("班次 发车时间 起点站 终点站 行车时间 额定载量 余票数量\n");

printf("%-010s%-010s%-010s%-010s%-010s%-010s%-010s\n",

cBList[i].C_ID,cBList[i].C_TIME,

cBList[i].C_ANAME,cBList[i].C_BNAME,cBList[i].C_USETIME,

cBList[i].C_MAXNUM,cBList[i].C_REMAINNUM );

printReturn("\n\t\t退票成功,回车返回");

return;

}

}

printReturn("\n\t指定班次不存在,回车键返回");

};

//更新车次信息

void update()

{

int flag;

char ID[20]={0};

setInfo("请输入要删除或修改的车次(请确认车次输入正确)",ID);

do

{

printf("\n\t按下列提示更新车次信息(退出修改请按0):");

printf("\n\t1:删除车次;2:修改发车时间;3:修改起点站;4:修改终点站;");

printf("\n\t5:修改行车时间;6:修改额定载量;7:修改余票数量;0:退出修改;");

printf("\n\t请选择:");

scanf("%d",&flag);

int i;

CardBase temp;

for(i=0;i

{

if(strcmp(cBList[i].C_ID,ID)==0)

{

if(flag==1) //删除车次信息

{

int j;

for(j=i;j

cBList[j]=cBList[j+1];//后面的数据覆盖前面的数据

cbNum--;//车次数减一

//保存到文件

writecardbasefile();

}

if(flag==2) //修改发车时间

{

setInfo("请输入新的发车时间",cBList[i].C_TIME);

temp=cBList[i];

//保存到文件

writecardbasefile();

}

if(flag==3) //修改起点站

{

setInfo("请输入新的起点站",cBList[i].C_ANAME);

temp=cBList[i];

//保存到文件

writecardbasefile();

}

if(flag==4) //修改终点站

{

setInfo("请输入新的终点站",cBList[i].C_BNAME);

temp=cBList[i];

//保存到文件

writecardbasefile();

}

if(flag==5) //修改行车时间

{

setInfo("请输入新的行车时间",cBList[i].C_USETIME);

temp=cBList[i];

//保存到文件

writecardbasefile();

}

if(flag==6) //修改额定载量

{

setInfo("请输入新的额定载量",cBList[i].C_MAXNUM);

temp=cBList[i];

//保存到文件

writecardbasefile();

}

if(flag==7) //修改余票数量

{

setInfo("请输入新的余票数量",cBList[i].C_REMAINNUM);

temp=cBList[i];

//保存到文件

writecardbasefile();

}

}

}

//当更新完成时呈现班次信息,如果删除了车次则不会呈现更新信息,即当flag值不为零时会触发更新

if(flag!=1&&flag!=0)

{ printf("更新后的班次信息\n");

printf("班次 发车时间 起点站 终点站 行车时间 额定载量 余票数量\n");

printf("%-010s%-010s%-010s%-010s%-010s%-010s%-010s\n",

temp.C_ID,temp.C_TIME,

temp.C_ANAME,temp.C_BNAME,temp.C_USETIME,

temp.C_MAXNUM,temp.C_REMAINNUM );

}

}while(flag);

printReturn("\n\t完成车次信息更新,回车键返回");

};

void mainmenu()

{

while(1)

{

char select;

do{

system("cls");//清屏

printf("\n\t ╭═════════■□■□═══╮");

printf("\n\t│ 火车班次系统 │");

printf("\n\t╰═══■□■□══════════╯");

printf("\n\t ┌────────────────┐");

printf("\n\t │1.录入班次 │");

printf("\n\t │2.浏览所有班次 │");

printf("\n\t │3.通过班次号查路线 │");

printf("\n\t │4.通过终点站查路线 │");

printf("\n\t │5.排序保存 │");

printf("\n\t │6.售票 │");

printf("\n\t │7.退票 │");

printf("\n\t │8.更新车次信息 │");

printf("\n\t │0.退出登录 │");

printf("\n\t └────────────────┘");

printf("\n\t 请选择:");

fflush(stdin);//清空输入缓冲区,通常是为了确保不影响后面的数据读取.

select=getchar();//等待用户输入数据

}while (select'8');

switch(select)

{

case '0':exit(0);break;

case '1':infoinput();break;

case '2':queryallinfo();break;

case '3':queryinfobyID();break;

case '4':queryinfobyBNAME();break;

case '5':sortSave();break;

case '6':sale();break;

case '7':back();break;

case '8':update();break;

}

}

}

//主函数

int main()

{

initsystem(); //系统初始化

while(1)

{

mainmenu();

}

}

程序中确实存在诸多问题;自己在调用系统函数方面还有提升空间;文件操作尚不熟练;热切期待与大家共同探讨与交流。

全部评论 (0)

还没有任何评论哟~