C程序课程设计之航班订票系统
前两天忙着改Paper的参考文献,今天终于搞定了,稍微舒了一口气,预祝我的Paper能够顺利发出。
今天早上要给大一的学弟讲C课程设计---航班订票系统。无奈时间不够,昨晚八九点才空下来有时间写代码,匆忙花点时间写好了,早上调试下Bug,就给学弟们讲去了。
航班订票系统的要求:
1)飞机信息及本飞机机票销售情况的存储结构。
飞机信息:飞机ID,航空公司,出发地、目的地、机票销售情况。
2)所有机票销售信息:飞机ID,机票号、购买者姓名、购买者身份证。
3)飞机管理(新增航班、停开航班)
4)飞机票查询(按目的地、按时间、按要求:靠窗、靠过道、n人连坐等)。
5)已售票信息查询
6)销售飞机票及办理退票
7)信息的存储和读取(读写文件)
这边,由于时间的关系,我对 7)没实现,另外,Dos下经典的界面也没去实现,就简单写了下前六个功能的实现。
另外,由于是C语言,结构体中无成员函数,因此需要定义函数来操作,这些函数需要传入结构体的指针。其实,某种意义上,可以认为C的文件,就是C++中的一个类(定义加实现)。
C系列语言的精髓就是指针,熟练操作指针,必须能够手动操纵指针,即malloc之类的函数使用。想下自己当初大一时写学生信息管理的课程设计,由于没学过链表之类的(高级)东西,恨死指针了! 现在回想起来,感觉指针是个好东西,虽然我现在还经常要调试指针引发的BUG..
题外话,用c来写这样的系统,个人感觉比C++麻烦。 看来,我开始接收面向对象思想了。。哈哈,好事。
按照题意的分析,我们可以知道,主要设计三个结构体:
Ticket: 机票信息
// 机票信息 struct Ticket{ int id; // 机票号 char buyerName[CHARLEN]; unsigned long buyerID;// 持票人 int price; // 价格 char postion; // AF 靠窗 CD 走道 A int line; // 第几排 };
Fly: 航班信息,其中要包含Ticket。内部有一个指向next Fly的指针
struct Fly{ int id; // 航班号 char company[CHARLEN]; // 航空公司 char source[CHARLEN]; // 出发地 char destination[CHARLEN]; // 目的地 int sold; // 已售票 struct LiftTime lift; struct Ticket*** ticket; // 本班飞机池 struct Fly* next; // 指向下一班飞机; };
Pool: 机场,即航班池,包含Fly链表的头指针。
struct Pool{ // 航班池 struct Fly* head; // struct Fly* tail; // 要让学弟自己实现tail的操作,所以就没用上这个tail int total; // 航班总数 };
由于结构体中定义了一堆的指针,因此我们在初始化的时候,就要注意下对指针符零值。 我在Fly结构体中的Ticket全用指针,前两个**表示第几列第几排,最后一个*表示实际要指向的Ticket位置。这样就节省了初始化的开支;若仅有两个**, 那势必要进行Ticket实体的初始化,这样就浪费了太多空间和时间了。因此,结构体中指向复杂的的成员数据,最好使用指针形式表示。同时,使用指针表示意味着以后操作就要使用malloc操作,在程序适当时候需要free掉,这样才不会造成内存泄露。
好的,其实代码不算很复杂,我就把代码全贴上来,主要从代码的注释中来看。
1 #ifndef MY_AIR_TICKET_H 2 #define MY_AIR_TICKET_H 3 #include <stdlib.h> 4 #include <stdio.h> 5 #include <string.h> 6 #define LINE 7 // 行数 7 #define COLUMN 6 // 列数 ABCDEF 8 #define CHARLEN 16 // 字符数组长度 9 #define TOTALTICKET (LINE*COLUMN) // 单一航班机票总数。 其实line和column应该要放在fly结构体中,这样能够自定义飞机的容量 10 enum Pos{A,B,C,D,E,F}; // A==0, 可以当做下标使用,这样代码更好读 11 enum REQUIRE{WINDOW, ASIDE, BINARY, TRIPLE}; 12 enum ISREMINDER{NO,YES}; // NO查询已售票 or YES余票 13 14 #define trace printf("line: %d\n",__LINE__) // 调试宏,适当的摆放,能够快速2分定位到错误的位置 15 16 // 机票信息 17 struct Ticket{ 18 int id; // 机票号 19 char buyerName[CHARLEN]; 20 unsigned long buyerID;// 持票人 21 int price; // 价格 22 char postion; // AF 靠窗 CD 走道 A 23 int line; // 第几排 24 }; 25 26 //struct Ticket* initTicket(void) 27 //{ 28 // struct Ticket* ticket = (struct Ticket*) malloc (sizeof(struct Ticket)); 29 // ticket->buyerID = 0; 30 // ticket->buyerName[0] = '\0'; 31 // ticket->id = 0; 32 // ticket->line = 0; 33 // ticket->postion = 0; 34 // ticket->price = 0; 35 // return ticket; 36 //} 37 38 struct Ticket* createTicket(int tid, char pos, int line, 39 char* bn, unsigned long bid,int prs) 40 { 41 struct Ticket* ticket = (struct Ticket*)malloc(sizeof(struct Ticket)); 42 ticket->id = tid; 43 ticket->postion = pos; 44 ticket->line = line; 45 strncpy(ticket->buyerName, bn, strlen(bn)+1); // 注意cpy要包含最后一个'\0' 46 ticket->buyerID = bid; 47 ticket->price = prs; 48 return ticket; // 这里的ticket是局部指针,为啥能返回呢?大家思考下哦。对于可以返回指针,这算是一种,因为它指向malloc出来的东西,这个东西在函数析构时不会消失。 49 } 50 51 void freeTicket(struct Ticket* t) 52 { 53 if (t != NULL) { // 最好进行free操作时,要先判断下非空 54 free(t); 55 } 56 } 57 struct LiftTime{ // 起飞时间结构体 58 unsigned char hour; 59 unsigned char minite; 60 }; 61 62 struct Fly{ 63 int id; // 航班号 64 char company[CHARLEN]; // 航空公司 65 char source[CHARLEN]; // 出发地 66 char destination[CHARLEN]; // 目的地 67 int sold; // 已售票 68 struct LiftTime lift; 69 struct Ticket*** ticket; // 本班飞机票池 70 struct Fly* next; // 指向下一班飞机; 71 }; 72 73 struct Fly* initFly() // 为了给机场类的head指针使用。 74 { 75 struct Fly* plane = (struct Fly*)malloc(sizeof(struct Fly)); 76 plane->id = 0; 77 plane->lift.hour = 0; 78 plane->lift.minite = 0; 79 plane->source[0] = '\n'; 80 plane->destination[0] = '\n'; 81 plane->company[0] = '\n'; 82 plane->next = NULL; 83 plane->sold = 0; 84 plane->next = NULL; 85 plane->ticket = NULL; 86 return plane; 87 } 88 89 struct Fly* createFly(int fid, char* from, char* to, struct LiftTime* lt, char* cmpy) // 真正的航班类创建 90 { 91 int i,j; 92 struct Fly* plane = (struct Fly*)malloc(sizeof(struct Fly)); 93 plane->id = fid; 94 plane->lift.hour = lt->hour; 95 plane->lift.minite = lt->minite; 96 strncpy(plane->source, from, strlen(from)+1); 97 strncpy(plane->destination, to, strlen(to)+1); 98 strncpy(plane->company, cmpy, strlen(cmpy)+1); 99 plane->next = NULL; 100 plane->sold = 0; 101 plane->next = NULL; 102 plane->ticket = (struct Ticket***)malloc(sizeof(struct Ticket**)*COLUMN); 从102--104其实就是C++中怎么new个二维数组的写法 103 for(i=0; i<COLUMN;++i) 104 plane->ticket[i] = (struct Ticket**) malloc(sizeof(struct Ticket*)*LINE); 105 for (i=0; i<COLUMN; ++i) { 106 for(j=0; j<LINE; ++j){ 107 plane->ticket[i][j] = NULL; 108 } 109 } 110 return plane; 111 } 112 void freeFly(struct Fly* f) 113 { 114 int i, j; 115 if (f != NULL) { 116 for (i=0; i<COLUMN; i++) { 117 for(j=0; j<LINE; j++){ 118 if(f->ticket == NULL) // 这里是一大疏忽点! 要是没这个判断,那么程序将会出错。那是因为head指针的ticket域为空! 119 break; 120 freeTicket(f->ticket[i][j]); 121 } 122 } 123 free(f->ticket); 124 free(f); 125 } 126 } 127 128 struct Pool{ // 航班池 129 struct Fly* head; 130 // struct Fly* tail; // 让学弟自己实现,因此我没做 131 int total; 132 }; 133 134 135 struct Pool* initPool() 136 { 137 struct Pool* p = (struct Pool*)malloc(sizeof(struct Pool)); 138 p->head = initFly(); // 唯一一次的initFly。 139 p->total = 0; 140 return p; 141 } 142 143 144 struct Pool* addFly(struct Pool* p, struct Fly* f) 145 { 146 if (p->head->next == NULL) { // 若无航班,则添加到头结点后 147 p->head->next = f; 148 p->total++; 149 }else{ // 添加到原有航班池最后。 有tail指针,一切将变得更加简单。。因此我们更要注意用空间换时间 150 struct Fly* tmp = p->head; 151 int t = p->total; 152 while(t--){ tmp = tmp->next;} 153 tmp->next = f; 154 p->total++; 155 } 156 return p; 157 } 158 159 int delFly(struct Pool* a, int id) // 根据航班Id删除航班 160 { 161 struct Fly* tmp; 162 struct Fly* p = a->head; 163 164 while( p && (p->next->id != id)){ 165 p = p->next; 166 } 167 if ( p == NULL || p->next == NULL) { 168 printf("No fly %d\n",id); 169 return 0; 170 } 171 tmp = p->next; 172 p->next = p->next->next; 173 freeFly(tmp); 174 a->total--; 175 printf("Delete fly %d\n",id); 176 return 1; 177 } 178 179 int delPool(struct Pool* p){ // 销毁机场 180 if( p != NULL){ 181 struct Fly* f = p->head->next; 182 struct Fly* tmp; 183 while(f != NULL){ 184 tmp = f->next; 185 freeFly(f); 186 f = tmp; 187 } 188 freeFly(p->head); 189 } 190 return 1; 191 } 192 193 194 int buyTicket(struct Fly* f, struct Ticket* t) //订票 195 { 196 int pos = t->postion - 'A'; 197 if ((f->ticket)[pos][t->line] != NULL) { 198 printf("Sorry, seat exist! please change another seat!\n"); 199 return 0; 200 } 201 (f->ticket)[pos][t->line] = t; 202 f->sold++; 203 printf("Book successfully!\n"); 204 return 1; 205 } 206 207 int delTicket(struct Fly* f, int tid) // 退票 208 { 209 int i,j; 210 for(i=0; i<COLUMN; i++){ 211 for(j=0; j<LINE; j++){ 212 if (((f->ticket)[i][j])->id == tid) { 213 freeTicket(((f->ticket)[i][j])); 214 ((f->ticket)[i][j]) = NULL; 215 f->sold--; 216 printf("ticket id %d successfully deleted!\n", tid); 217 return 1; 218 } 219 } 220 } 221 printf("No %d ticket exist!\n",tid); 222 return 0; 223 } 224 225 void showFlyInfo(struct Fly* f) 226 { 227 printf("Plane %d: %s--->%s, lift: %2d:%2d | Remind Ticket %d/%d , Company of %s\n", 228 f->id, f->source, f->destination, f->lift.hour, f->lift.minite, TOTALTICKET-f->sold,TOTALTICKET, f->company); 229 } 230 231 int showTicketInfo(struct Fly* f, int tid) 232 { 233 int i,j; 234 showFlyInfo(f); 235 for (i=0; i<COLUMN; i++) { 236 for (j=0; j<LINE; j++) { 237 if ( (f->ticket[i][j] != NULL) && (f->ticket[i][j]->id == tid)) { 238 printf("Ticket id: %d , price: %d\tName: %s ID: %ld\n", 239 f->ticket[i][j]->id, 240 f->ticket[i][j]->price, 241 f->ticket[i][j]->buyerName, 242 f->ticket[i][j]->buyerID); 243 return 1; 244 } 245 } 246 } 247 return 0; 248 } 249 // 根据出发目的地查询航班 250 void searchByDST(struct Pool* p, char* from, char* to) 251 { 252 struct Fly* plane = p->head->next; 253 int i; 254 for(i=1; plane && (i<p->total); ++i){ 255 if( !strcmp(from, plane->source) && !strcmp(to,plane->destination)){ 256 showFlyInfo (plane); 257 } 258 plane = plane->next; 259 } 260 } 261 // 时间段查询航班 262 void searchByTime(struct Pool* p, unsigned char start, unsigned char last) 263 { 264 struct Fly* plane = p->head->next; 265 int i; 266 for(i=0; plane && (i<p->total); ++i){ 267 if( (plane->lift.hour>=start) && (plane->lift.hour <= last) ){ 268 showFlyInfo (plane); 269 } 270 plane = plane->next; 271 } 272 } 273 274 // 按要求查询,这段代码其实可以重构下,太多相似的东西了。 275 void searchByRequire(struct Fly* f, enum REQUIRE r, enum ISREMINDER c) 276 { 277 int i,j; 278 int count = 1; 279 switch(r) 280 { 281 case WINDOW: 282 if (c == YES) { 283 printf("Search by Window remind:\n"); 284 }else{ 285 printf("Search by Window Sold:\n"); 286 } 287 for(i=0; i<COLUMN; i+=(COLUMN-1)){ 288 for (j=0; j<LINE; j++) { 289 if ( ((f->ticket[i][j] == NULL) && (c==YES)) 290 || ((f->ticket[i][j] != NULL) && (c==NO))) 291 { 292 count++; 293 printf("%c%2d ", i+'A',j); 294 } 295 if (count % 8 == 0) { printf("\n");} 296 } 297 } 298 putchar('\n'); 299 break; 300 case ASIDE: 301 if (c == YES) { 302 printf("Search by Aside remind:\n"); 303 }else{ 304 printf("Search by Aside Sold:\n"); 305 } 306 for(i=C; i<=D; i++){ 307 for (j=0; j<LINE; j++) { 308 if ( ((f->ticket[i][j] == NULL) && (c==YES)) 309 || ((f->ticket[i][j] != NULL) && (c==NO))) 310 { 311 count++; 312 printf("%c%2d ", i+'A',j); 313 } 314 if (count % 8 == 0) { printf("\n");} 315 } 316 } 317 putchar('\n'); 318 break; 319 case BINARY: 320 if (c == NO) { 321 printf("Twins seats sold:\n"); 322 for(j=0; j<LINE; ++j){ 323 if (f->ticket[B][j] != NULL) { 324 if(f->ticket[A][j] != NULL){ 325 printf("(%c%d, %c%d) ",'A',j,'B',j); 326 count++; 327 if (count % 8 == 0) { printf("\n");} 328 } 329 if(f->ticket[C][j] != NULL){ 330 printf("(%c%d, %c%d) ",'B',j,'C',j); 331 count++; 332 if (count % 8 == 0) { printf("\n");} 333 } 334 } 335 if (f->ticket[E][j] != NULL) { 336 if(f->ticket[D][j] != NULL){ 337 printf("(%c%d, %c%d) ",'D',j,'E',j); 338 count++; 339 if (count % 8 == 0) { printf("\n");} 340 } 341 if(f->ticket[F][j] != NULL){ 342 printf("(%c%d, %c%d) ",'E',j,'F',j); 343 count++; 344 if (count % 8 == 0) { printf("\n");} 345 } 346 } 347 } 348 349 } 350 if (c == YES){ 351 printf("Twins seats remaid:\n"); 352 for(j=0; j<LINE; ++j){ 353 if(f->ticket[B][j] == NULL){ 354 if(f->ticket[A][j] == NULL){ 355 printf("(%c%d, %c%d) ",'A',j,'B',j); 356 count++; 357 if (count % 8 == 0) { printf("\n");} 358 } 359 if(f->ticket[C][j] == NULL){ 360 printf("(%c%d, %c%d) ",'B',j,'C',j); 361 count++; 362 if (count % 8 == 0) { printf("\n");} 363 } 364 } 365 if(f->ticket[E][j] == NULL){ 366 if(f->ticket[D][j] == NULL){ 367 printf("(%c%d, %c%d) ",'D',j,'E',j); 368 count++; 369 if (count % 8 == 0) { printf("\n");} 370 } 371 if(f->ticket[F][j] == NULL){ 372 printf("(%c%d, %c%d) ",'E',j,'F',j); 373 count++; 374 if (count % 8 == 0) { printf("\n");} 375 } 376 } 377 } 378 } 379 putchar('\n'); 380 break; 381 case TRIPLE: 382 if(c == NO){ 383 printf("Triple seats:\n"); 384 for(j=0; j<LINE; ++j){ 385 if(f->ticket[B][j] != NULL) 386 if(f->ticket[A][j] != NULL) 387 if(f->ticket[C][j] != NULL){ 388 printf("(%c%d--%c%d) ",'A',j,'C',j); 389 count++; 390 if (count % 4 == 0) { printf("\n");} 391 } 392 393 if(f->ticket[E][j] != NULL) 394 if(f->ticket[D][j] != NULL) 395 if(f->ticket[F][j] != NULL){ 396 printf("(%c%d--%c%d) ",'D',j,'F',j); 397 count++; 398 if (count % 4 == 0) { printf("\n");} 399 } 400 } 401 } 402 if(c == YES){ 403 printf("Triple seats:\n"); 404 for(j=0; j<LINE; ++j){ 405 if(f->ticket[B][j] == NULL) 406 if(f->ticket[A][j] == NULL) 407 if(f->ticket[C][j] == NULL){ 408 printf("(%c%d--%c%d) ",'A',j,'C',j); 409 count++; 410 if (count % 4 == 0) { printf("\n");} 411 } 412 413 if(f->ticket[E][j] == NULL) 414 if(f->ticket[D][j] == NULL) 415 if(f->ticket[F][j] == NULL){ 416 printf("(%c%d--%c%d) ",'D',j,'F',j); 417 count++; 418 if (count % 4 == 0) { printf("\n");} 419 } 420 } 421 } 422 putchar('\n'); 423 break; 424 } 425 printf("\n"); 426 } 427 #endif 428 429 void main() 430 { 431 struct Pool* airport = initPool(); 432 struct LiftTime flt1 = {10,10}; 433 struct LiftTime flt2 = {6,40}; 434 struct Fly* f1 = createFly(1,"Xiamen","Beijing", &flt1, "xmu"); 435 struct Fly* f2 = createFly(2,"Fuzhou","Beijing", &flt2, "xmu"); 436 addFly(airport, f1); 437 addFly(airport, f2); 438 buyTicket (f1, createTicket(1,'A',3, "zy",1234567,400)); 439 buyTicket (f1, createTicket(2,'B',3,"xld",2345678,400)); 440 showTicketInfo (f1,1); 441 showTicketInfo (f1,2); 442 searchByTime (airport,8,12); 443 searchByDST (airport,"Fuzhou","Beijing"); 444 searchByRequire (f1,BINARY,YES); 445 delPool (airport); 446 }
测试代码结果: