基于C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單的12306火車售票系統(tǒng)
程序設(shè)計(jì)要求用C語(yǔ)言寫一個(gè)簡(jiǎn)單的火車售票系統(tǒng),主要實(shí)現(xiàn)的功能為:
錄入班次信息
瀏覽班次信息
按班次號(hào)查詢
按終點(diǎn)站查詢
按余票數(shù)量排序保存
售票
退票
更新班次信息
退出系統(tǒng)
所有的班次信息保存在number.dat文件中,排序過(guò)后的保存在sort.dat中(.dat是一種二進(jìn)制文件)。
在編寫的過(guò)程中我覺得在判斷火車的狀態(tài)比較值得深究。這里假設(shè)火車主要有四種狀態(tài):
1.未發(fā)車
2.已發(fā)車
3.停止檢票
4.停止退票
在程序中,思路是將代表發(fā)車時(shí)間的字符串轉(zhuǎn)化為整型,再和系統(tǒng)現(xiàn)在的時(shí)間進(jìn)行大小比較,主要采用if判斷各種情況。其中atime代表的是發(fā)車時(shí)間的整型數(shù),btime代表的是系統(tǒng)時(shí)間的整型數(shù),具體實(shí)現(xiàn)如下:
if(atime<=btime) //已經(jīng)發(fā)車 return 1; if(((atime-btime<=30)&&(atime-btime>5)&&(atime/100==btime/100))||(((atime%100+(60-btime%100))<=30)&&(atime%100+(60-btime%100))>5&&(atime/100-btime/100==1))) //距發(fā)車半小時(shí)以內(nèi),停止退票,%表示取余 return 2; if(((atime-btime<=5)&&(atime/100==btime/100))||((atime%100+(60-btime%100)&&(atime/100-btime/100==1))<=5)) //距發(fā)車前五分鐘內(nèi)停止檢票 return 3; return 0; //可以辦理購(gòu)?fù)似?/pre>
在判斷退票時(shí)如果兩個(gè)時(shí)間的小時(shí)數(shù)是一樣的,則它們的分鐘數(shù)如果相差在30之內(nèi)即半小時(shí)之內(nèi)或者發(fā)車時(shí)間的小時(shí)和系統(tǒng)時(shí)間的小時(shí)相差一個(gè)1,并且發(fā)車時(shí)間的分鐘數(shù)小于30,系統(tǒng)時(shí)間的分鐘大于30,則它們之間也就相差在30之內(nèi),此時(shí)代表停止退票。
判斷檢票和上面思想大致相同。
為了參考研究,貼上代碼:
#include<stdio.h> #include<stdlib.h> #include<conio.h> #include<string.h> #include "time.h" //班次信息表 #define SIZELIMIT 10 //每班次的具體信息的字符個(gè)數(shù)限制在10以內(nèi) #define MAXNUM 1000 //設(shè)定最多只能錄入1000個(gè)車次信息 typedef struct cardbase //定義一個(gè)關(guān)于班次信息的結(jié)構(gòu)體,取名為CardBase { char C_ID[SIZELIMIT];//班次 char C_TIME[SIZELIMIT];//發(fā)車時(shí)間 char C_ANAME[SIZELIMIT];//起點(diǎn)站 char C_BNAME[SIZELIMIT];//終點(diǎn)站 char C_USETIME[SIZELIMIT];//行車時(shí)間 char C_MAXNUM[SIZELIMIT];//額定載量 char C_REMAINNUM[SIZELIMIT];//余票數(shù)量 }CardBase; int cbNum=0;//記錄班次數(shù) CardBase cBList[MAXNUM];//班次列表 //讀取班次信息 void readcardbasefile() { FILE *fp; //打開文件失敗則創(chuàng)建文件 if((fp=fopen("./number.dat","r"))==NULL) { //初次運(yùn)行創(chuàng)建文件 if ((fp=fopen("./number.dat","w"))==NULL) { exit(0); //返回 } else { fclose(fp); } return ; } /*文件位置指針移動(dòng)到文件末尾*/ fseek(fp,0,2);//重定位文件內(nèi)部位置指針 /* int fseek( FILE *stream, long offset, int origin ); 第一個(gè)參數(shù)stream為文件指針 第二個(gè)參數(shù)offset為偏移量,正數(shù)表示正向偏移,負(fù)數(shù)表示負(fù)向偏移 第三個(gè)參數(shù)origin設(shè)定從文件的哪里開始偏移,可能取值為:SEEK_CUR、 SEEK_END 或 SEEK_SET SEEK_SET: 文件開頭 SEEK_CUR: 當(dāng)前位置 SEEK_END: 文件結(jié)尾 其中SEEK_SET,SEEK_CUR和SEEK_END依次為0,1和2. 簡(jiǎn)言之: fseek(fp,100L,0);把stream指針移動(dòng)到離文件開頭100字節(jié)處; fseek(fp,100L,1);把stream指針移動(dòng)到離文件當(dāng)前位置100字節(jié)處; fseek(fp,-100L,2);把stream指針退回到離文件結(jié)尾100字節(jié)處。 */ if (ftell(fp)>0)//文件不為空 /*ftell函數(shù)用于得到文件位置指針當(dāng)前位置相對(duì)于文件首的偏移字節(jié)數(shù) 也就是得到文件所包含的字節(jié)數(shù),如果大于0,則代表文件非空*/ { //文件位置指針移動(dòng)到文件開始 rewind(fp); char buff[10]={0}; for (cbNum=0;!feof(fp) && fread(&cBList[cbNum],sizeof(CardBase),1,fp);cbNum++) /*對(duì)于feof函數(shù),如果遇到文件結(jié)束,函數(shù)feof(fp)的值為非零值,否則為0。 即如果文件結(jié)束,!feof(fp)為0,跳出循環(huán) 對(duì)于fread函數(shù),是從一個(gè)文件流中讀數(shù)據(jù),如果調(diào)用成功返回實(shí)際讀取到的項(xiàng)個(gè)數(shù), 如果不成功或讀到文件末尾返回 0*/ fgets(buff,10,fp); /*char *fgets(char *buf, int bufsize, FILE *stream); 從文件結(jié)構(gòu)體指針stream中讀取數(shù)據(jù),每次讀取一行。讀取的數(shù)據(jù)保存在buf指向的字符數(shù)組中, 每次最多讀取bufsize-1個(gè)字符(第bufsize個(gè)字符賦'\0'),如果文件中的該行,不足bufsize個(gè)字符, 則讀完該行就結(jié)束。如若該行(包括最后一個(gè)換行符)的字符數(shù)超過(guò)bufsize-1,則fgets只返回一個(gè)不完整的行, 但是,緩沖區(qū)總是以NULL字符結(jié)尾,對(duì)fgets的下一次調(diào)用會(huì)繼續(xù)讀該行。函數(shù)成功將返回buf,失敗或讀到文件結(jié)尾返回NULL。 因此我們不能直接通過(guò)fgets的返回值來(lái)判斷函數(shù)是否是出錯(cuò)而終止的,應(yīng)該借助feof函數(shù)或者ferror函數(shù)來(lái)判斷。 */ fclose(fp); } else { fclose(fp); } return; } //保存班次信息 void writecardbasefile() { int i; FILE *fp; if ((fp=fopen("./number.dat","w"))==NULL) { printf("系統(tǒng)錯(cuò)誤"); } char buff[10]={0}; strcpy(buff,"\r\n"); for (i=0;i<cbNum;i++) { if (fwrite(&cBList[i],sizeof(CardBase),1,fp)!=1) { printf("系統(tǒng)錯(cuò)誤"); } if (fwrite(buff,2,1,fp)!=1) { printf("系統(tǒng)錯(cuò)誤"); } } fclose(fp); } //保存排序信息 void writesortfile() { int i; FILE *fp; if ((fp=fopen("./sort.dat","w"))==NULL) { printf("系統(tǒng)錯(cuò)誤"); } char buff[10]={0}; strcpy(buff,"\r\n"); for (i=0;i<cbNum;i++) { if (fwrite(&cBList[i],sizeof(CardBase),1,fp)!=1) { printf("系統(tǒng)錯(cuò)誤"); } if (fwrite(buff,2,1,fp)!=1) { printf("系統(tǒng)錯(cuò)誤"); } } fclose(fp); } //打印并輸入后返回 void printReturn(char *info) { printf("\n\n\t %s",info); fflush(stdin);//清空輸入緩沖區(qū),通常是為了確保不影響后面的數(shù)據(jù)讀取. getchar(); } //輸入信息 void setInfo(char pinfo[1024],char desinfo[]) { printf("\n\t%s:",pinfo); fflush(stdin); scanf("%s",desinfo); } //系統(tǒng)初始化 void initsystem() { readcardbasefile(); }; //錄入班次 void infoinput() { setInfo("班次",cBList[cbNum].C_ID); setInfo("發(fā)車時(shí)間(24小時(shí)制)",cBList[cbNum].C_TIME); setInfo("起點(diǎn)站",cBList[cbNum].C_ANAME); setInfo("終點(diǎn)站",cBList[cbNum].C_BNAME); setInfo("行車時(shí)間",cBList[cbNum].C_USETIME); setInfo("額定載量",cBList[cbNum].C_MAXNUM); setInfo("余票數(shù)量",cBList[cbNum].C_REMAINNUM); cbNum++; writecardbasefile(); printReturn("\n\t錄入成功,回車鍵返回"); }; //時(shí)間比較 int timecmp(char A[10]) { //將火車時(shí)間轉(zhuǎn)成整數(shù) char tempa[10]={0}; int ta=0; int i; for(i=0;i<strlen(A);i++) if(A[i]!=':'&&A[i]!=':') //冒號(hào)的中文輸入和英文輸入 { tempa[ta]=A[i]; ta++; } int atime=atoi(tempa);//把字符串變成整型 //獲取系統(tǒng)時(shí)間 char tempb[10]={0}; time_t t = time(0); strftime( tempb, 10, "%H%M",localtime(&t) ); int btime=atoi(tempb); //比較 if(atime<=btime) //已經(jīng)發(fā)車 return 1; if(((atime-btime<=30)&&(atime-btime>5)&&(atime/100==btime/100))||(((atime%100+(60-btime%100))<=30)&&(atime%100+(60-btime%100))>5&&(atime/100-btime/100==1))) //距發(fā)車半小時(shí)以內(nèi),停止退票,%表示取余 return 2; if(((atime-btime<=5)&&(atime/100==btime/100))||((atime%100+(60-btime%100)&&(atime/100-btime/100==1))<=5)) //距發(fā)車前五分鐘內(nèi)停止檢票 return 3; return 0; //可以辦理購(gòu)?fù)似? } //瀏覽所有班次 void queryallinfo() { printf("班次信息\n"); printf("班次 發(fā)車時(shí)間 起點(diǎn)站 終點(diǎn)站 行車時(shí)間 額定載量 余票數(shù)量 狀態(tài)\n"); int i; for(i=0;i<cbNum;i++) { char temp[20]={0}; strcpy(temp,"未發(fā)車"); if(1==timecmp(cBList[i].C_TIME)) strcpy(temp,"已發(fā)車"); 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回車鍵返回"); }; //通過(guò)班次號(hào)查路線 void queryinfobyID() { char ID[20]={0}; setInfo("輸入班次號(hào)",ID); int i; for( i=0;i<cbNum;i++) { if(strcmp(cBList[i].C_ID,ID)==0) { printf("班次信息\n"); printf("班次 發(fā)車時(shí)間 起點(diǎn)站 終點(diǎn)站 行車時(shí)間 額定載量 余票數(shù)量\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指定信息不存在,回車鍵返回"); }; //通過(guò)終點(diǎn)站查路線 void queryinfobyBNAME() { char Name[20]={0}; setInfo("輸入終點(diǎn)站",Name); int i; for(i=0;i<cbNum;i++) { if(strcmp(cBList[i].C_BNAME,Name)==0) { printf("班次信息\n"); printf("班次 發(fā)車時(shí)間 起點(diǎn)站 終點(diǎn)站 行車時(shí)間 額定載量 余票數(shù)量\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指定信息不存在,回車鍵返回"); }; //排序按余票數(shù)量排序保存 void sortSave() { //冒泡排序 int i,j; for(i=0;i<cbNum;i++) for(j=0;j<cbNum-i-1;j++) { if(atoi(cBList[j].C_REMAINNUM)<atoi(cBList[j+1].C_REMAINNUM)) { CardBase temp=cBList[j]; cBList[j]=cBList[j+1]; cBList[j+1]=temp; } } //打印排序結(jié)果 queryallinfo(); //保存排序結(jié)果 writesortfile(); }; //售票 void sale() { char ID[20]={0}; setInfo("輸入班次號(hào)",ID); int i; for(i=0;i<cbNum;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;//確保余票不為負(fù)數(shù) _itoa(temp,cBList[i].C_REMAINNUM,10); //保存到文件 writecardbasefile(); printf("班次信息\n"); printf("班次 發(fā)車時(shí)間 起點(diǎn)站 終點(diǎn)站 行車時(shí)間 額定載量 余票數(shù)量\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("輸入班次號(hào)",ID); int i; for(i=0;i<cbNum;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("班次 發(fā)車時(shí)間 起點(diǎn)站 終點(diǎn)站 行車時(shí)間 額定載量 余票數(shù)量\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("請(qǐng)輸入要?jiǎng)h除或修改的車次(請(qǐng)確認(rèn)車次輸入正確)",ID); do { printf("\n\t按下列提示更新車次信息(退出修改請(qǐng)按0):"); printf("\n\t1:刪除車次;2:修改發(fā)車時(shí)間;3:修改起點(diǎn)站;4:修改終點(diǎn)站;"); printf("\n\t5:修改行車時(shí)間;6:修改額定載量;7:修改余票數(shù)量;0:退出修改;"); printf("\n\t請(qǐng)選擇:"); scanf("%d",&flag); int i; CardBase temp; for(i=0;i<cbNum;i++) { if(strcmp(cBList[i].C_ID,ID)==0) { if(flag==1) //刪除車次信息 { int j; for(j=i;j<cbNum;j++) cBList[j]=cBList[j+1];//后面的數(shù)據(jù)覆蓋前面的數(shù)據(jù) cbNum--;//車次數(shù)減一 //保存到文件 writecardbasefile(); } if(flag==2) //修改發(fā)車時(shí)間 { setInfo("請(qǐng)輸入新的發(fā)車時(shí)間",cBList[i].C_TIME); temp=cBList[i]; //保存到文件 writecardbasefile(); } if(flag==3) //修改起點(diǎn)站 { setInfo("請(qǐng)輸入新的起點(diǎn)站",cBList[i].C_ANAME); temp=cBList[i]; //保存到文件 writecardbasefile(); } if(flag==4) //修改終點(diǎn)站 { setInfo("請(qǐng)輸入新的終點(diǎn)站",cBList[i].C_BNAME); temp=cBList[i]; //保存到文件 writecardbasefile(); } if(flag==5) //修改行車時(shí)間 { setInfo("請(qǐng)輸入新的行車時(shí)間",cBList[i].C_USETIME); temp=cBList[i]; //保存到文件 writecardbasefile(); } if(flag==6) //修改額定載量 { setInfo("請(qǐng)輸入新的額定載量",cBList[i].C_MAXNUM); temp=cBList[i]; //保存到文件 writecardbasefile(); } if(flag==7) //修改余票數(shù)量 { setInfo("請(qǐng)輸入新的余票數(shù)量",cBList[i].C_REMAINNUM); temp=cBList[i]; //保存到文件 writecardbasefile(); } } } //更改完成后顯示更新后的班次信息,如果是刪除車次則不顯示,即flag不等于0的時(shí)候顯示更新信息 if(flag!=1&&flag!=0) { printf("更新后的班次信息\n"); printf("班次 發(fā)車時(shí)間 起點(diǎn)站 終點(diǎn)站 行車時(shí)間 額定載量 余票數(shù)量\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│ 火車班次系統(tǒng) │"); printf("\n\t╰═══■□■□══════════╯"); printf("\n\t ┌────────────────┐"); printf("\n\t │1.錄入班次 │"); printf("\n\t │2.瀏覽所有班次 │"); printf("\n\t │3.通過(guò)班次號(hào)查路線 │"); printf("\n\t │4.通過(guò)終點(diǎn)站查路線 │"); 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 請(qǐng)選擇:"); fflush(stdin);//清空輸入緩沖區(qū),通常是為了確保不影響后面的數(shù)據(jù)讀取. select=getchar();//等待用戶輸入數(shù)據(jù) }while (select<'0'||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; } } } //主函數(shù) int main() { initsystem(); //系統(tǒng)初始化 while(1) { mainmenu(); } }
程序中肯定還存在很多問(wèn)題,自己對(duì)調(diào)用系統(tǒng)函數(shù)方面還有很多需要學(xué)習(xí),文件的操作也不是很熟練,歡迎大家一起探討交流。
相關(guān)文章
C++如何實(shí)現(xiàn)定長(zhǎng)內(nèi)存池詳解
內(nèi)存池根據(jù)存儲(chǔ)的元素的長(zhǎng)度是否可變,分為變長(zhǎng),與定長(zhǎng)兩種內(nèi)存池,這篇文章主要給大家介紹了關(guān)于C++如何實(shí)現(xiàn)定長(zhǎng)內(nèi)存池的相關(guān)資料,需要的朋友可以參考下2021-09-09C++實(shí)現(xiàn)圖像目標(biāo)區(qū)裁剪ImageCropping
本文主要介紹了C++實(shí)現(xiàn)圖像目標(biāo)區(qū)裁剪ImageCropping,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06Opencv基于文字檢測(cè)去圖片水印的實(shí)現(xiàn)示例
去水印是個(gè)麻煩事,本文就來(lái)介紹一種方法Opencv基于文字檢測(cè)去圖片水印的實(shí)現(xiàn)示例,具有一定的參考價(jià)值,感興趣的可以了解一下2023-09-09