来吧,接下来是各个功能的函数的实现代码。
首先,程序运行时加载读入账户信息和航班信息。接下来就该读取文件了。
我把账户资料和航班信息储存在了.txt文件里
那么问题就来了,挖掘机...额,不对,应该怎么读入账户资料和航班信息?
每一行是结构体的一个成员,我读入的方式是一行一行读入。
两个读入函数代码如下:
1 //读入账户信息 2 BOOL ReadAccountData(HWND hwndDlg){ 3 4 FILE *fp; 5 6 passenger = (Passenger *)malloc(sizeof(Passenger)); //为登录账户分配内存 7 if (!passenger){ 8 MessageBox(hwndDlg, TEXT("内存申请错误!"), TEXT("错误"), MB_OK | MB_ICONERROR); 9 EndDialog(hwndDlg, 0);10 return FALSE;11 }//if12 13 psglink.head = NULL;14 psglink.tail = NULL;15 psglink.PsgNum = 0;16 17 if ((fp = fopen(".\\AccountData.txt", "r+")) == NULL){ //打开文件18 MessageBox(hwndDlg, TEXT("账户文件读入错误!"), TEXT("错误"), MB_OK | MB_ICONERROR);19 EndDialog(hwndDlg, 0);20 }//if 21 22 while (!feof(fp)){23 Passenger *p = (Passenger *)malloc(sizeof(Passenger));24 if (!p){25 MessageBox(hwndDlg, TEXT("内存申请错误!"), TEXT("错误"), MB_OK | MB_ICONERROR);26 EndDialog(hwndDlg, 0);27 return FALSE;28 }//if29 30 //读入账户姓名、身份证号、密码31 if (fscanf(fp, "%s%s%s", p->Name, p->IdNum, p->PassWord) == EOF){32 free(p); break;33 }34 35 p->Next = NULL;36 if (psglink.head == NULL) //读入第一个账户信息时,头、尾结点均指向p37 psglink.head = p;38 else39 psglink.tail->Next = p; //否则,尾结点Next指向p40 psglink.tail = p; //尾结点指向p41 psglink.PsgNum++; //已注册账户个数42 43 }//while44 fclose(fp); //关闭文件45 return TRUE;46 }//ReadAccountData(HWND)47 48 49 //读入航班信息50 BOOL ReadFlightData(HWND hwndDlg){ 51 52 int flag = 0;53 FILE *fp;54 55 flightlink.Flight_Number = 0;56 flightlink.head = NULL;57 flightlink.tail = NULL;58 59 if ((fp = fopen(".\\FlightData.txt", "r")) == NULL){ //打开文件60 MessageBox(hwndDlg, TEXT("账户文件读入错误!"), TEXT("错误"), MB_OK | MB_ICONERROR);61 EndDialog(hwndDlg, 0);62 }//if63 64 while (!feof(fp)){65 Flight *p = (Flight *)malloc(sizeof(Flight));66 if (!p){67 MessageBox(hwndDlg, TEXT("内存申请错误!"), TEXT("错误"), MB_OK | MB_ICONERROR);68 EndDialog(hwndDlg, 0);69 return FALSE;70 }//if71 //读入航班信息72 if (fscanf(fp, "%s%lf%s%d%d%s%s%s%s%s",73 p->Flight_Number,74 &p->Fare,75 p->Discount,76 &p->Seat_Number,77 &p->Vacant_Seat,78 p->Departure,79 p->Destination,80 p->Date,81 p->TakeOff_Time,82 p->Landing_Time) == EOF)83 {84 free(p);85 break;86 }87 p->Next = NULL;88 if (flightlink.head == NULL) //添加至链表89 flightlink.head = p; 90 else91 flightlink.tail->Next = p;92 flightlink.tail = p;93 flightlink.Flight_Number++;94 95 }//while96 fclose(fp); //关闭文件97 return TRUE;98 }//ReadFlightData()
因为开发环境是vs2013,所以编译时会报错,报错信息是大体是说fopen()函数不安全,根据提示信息,解决办法是在文件头部做如下定义:
1 #define _CRT_SECURE_NO_WARNINGS
或者是在项目->属性->c/c++->预处理器->预处理器定义,后面加上_CRT_SECURE_NO_WARNINGS就行了。
结下来又遇到问题了:程序退出把数据写入txt文件时每行末尾都会有一个\n,读入数据的时候用的是feof()函数,而feof()返回的其实是"最后一次读操作的内容",与数据库中的eof()不同,eof()读取的是当前指针位置。因此在读到文件末尾的时候,程序会多执行一次循环,为了防止这种情况,我采取的是检查fscanf()返回值的方法,在此以读入账户资料时为例:
1 //读入账户姓名、身份证号、密码2 if (fscanf(fp, "%s%s%s", p->Name, p->IdNum, p->PassWord) == EOF){3 free(p); break;4 }
然后是用户登录或注册时所用到的函数:
1 //登陆用户验证 2 BOOL AccountLogIn(HWND hwndDlg){ 3 4 int flag = 0; //flag!=0则该用户已注册,flag==0则该用户尚未注册 5 Passenger *p; 6 7 GetDlgItemText(hwndDlg, IDC_IDEDIT, passenger->IdNum, 256); //获取用户输入ID 8 GetDlgItemText(hwndDlg, IDC_PSWEDIT, passenger->PassWord, 256); //获取用户输入密码 9 10 p = psglink.head;11 while (p){ //在用户链表查找登陆用户ID12 if (!lstrcmp(passenger->IdNum, p->IdNum)){ 13 flag++; //该用户已注册14 if (!lstrcmp(passenger->PassWord, p->PassWord)){ //密码匹配,登陆成功15 lstrcpy(passenger->Name, p->Name);16 MessageBox(hwndDlg, TEXT("登陆成功,单击确定进入程序主界面"), TEXT("登陆成功"), MB_OK | MB_ICONINFORMATION);17 break;18 }//if19 else{ //密码错误,退出循环20 MessageBox(hwndDlg, TEXT("密码错误,请重新输入"), TEXT("密码错误"), MB_OK | MB_ICONERROR);21 return FALSE;22 }//else23 }//if24 p = p->Next;25 }//while26 if (!flag){ //用户尚未注册27 if (lstrlen(passenger->PassWord)==0)28 MessageBox(hwndDlg, TEXT("请输入密码!"), TEXT("信息"), MB_OK | MB_ICONINFORMATION);29 else30 MessageBox(hwndDlg, TEXT("该账户尚未注册,请先注册"), TEXT("信息"), MB_OK | MB_ICONINFORMATION);31 }//if32 else{ //关闭登陆界面,弹出主界面33 EndDialog(hwndDlg, TRUE);34 if (ReadAccountOrder(hwndDlg, passenger)) //读取用户订单35 DialogBox(hInst, MAKEINTRESOURCE(IDD_MAINDLG), NULL, (DLGPROC)MainDlgProc);36 }//else37 38 return TRUE;39 }//AccountLogIn(HWND)
1 //用户注册 2 BOOL AccountRegister(HWND hwndDlg){ 3 4 GetDlgItemText(hwndDlg, IDC_IDEDIT, passenger->IdNum, 256); //获取用户输入ID 5 GetDlgItemText(hwndDlg, IDC_PSWEDIT, passenger->PassWord, 256); //获取用户输入密码 6 7 if (lstrlen(passenger->PassWord) == 0){ 8 MessageBox(hwndDlg, TEXT("请输入注册用户密码!"), TEXT("信息"), MB_OK | MB_ICONINFORMATION); 9 return FALSE;10 }11 12 DialogBox(hInst, MAKEINTRESOURCE(IDD_NAMEDLG), NULL, (DLGPROC)NameDlgProc); //获取新注册用户姓名13 14 if (lstrlen(passenger->Name) == 0)15 return FALSE;16 17 passenger->Next = NULL;18 19 if (psglink.head == NULL) //该注册账户为第一个账户时,头、尾结点均指向passenger20 psglink.head = passenger;21 else22 psglink.tail->Next = passenger; //将新注册账户资料添加至账户链表23 psglink.tail = passenger; //链表尾指针指向链表尾24 psglink.PsgNum++; //注册用户数目加125 passenger->TicketNum = 0; 26 passenger->OrderLink.head = NULL; //乘客订单链表初始化27 passenger->OrderLink.tail = NULL;28 passenger->OrderLink.OrderNum = 0;29 30 MessageBox(hwndDlg, TEXT("注册成功!请单击确定进入主界面"), TEXT("注册成功"), MB_OK | MB_ICONINFORMATION);31 32 EndDialog(hwndDlg, TRUE); //关闭登陆界面33 34 DialogBox(hInst, MAKEINTRESOURCE(IDD_MAINDLG), NULL, (DLGPROC)MainDlgProc); //弹出主界面35 36 return TRUE;37 }//AccountRegister(HWND)
点击查找、订票、退票、航班录入、修改航班信息按钮都会调用相应的函数。下面来看实现各个功能的代码:
1 //查找航班 2 BOOL SearchFlight(HWND hMainDlg){ 3 int flag1 = 0; //if(flag1==0) 出发地、目的地查询航班,else:航班号查航班 4 int flag2 = 0; 5 Flight *p; 6 TCHAR szBuffer[256] = {TEXT("\0")}; 7 TCHAR szDeparture[16], szDestination[16], szFltNum[16], szDate[16]; 8 9 HWND hEdit = GetDlgItem(hMainDlg, IDC_INFORMATION);10 11 GetDlgItemText(hMainDlg, IDC_DEPARTURE, szDeparture, 15); //获取用户输入出发地12 GetDlgItemText(hMainDlg, IDC_DESTINATION, szDestination, 15); //获取用户输入目的地13 GetDlgItemText(hMainDlg, IDC_FLIGHTNUM, szFltNum, 15); //获取用户输入航班号14 GetDlgItemText(hMainDlg, IDC_DATE, szDate, 15); //获取用户选择航班时间15 16 SetDlgItemText(hMainDlg, IDC_INFORMATION, szBuffer); //清空航班信息区域文本17 18 19 if (lstrlen(szFltNum) || (!(lstrlen(szDeparture)) && !(lstrlen(szDestination))))20 flag1++;21 else if (!(lstrlen(szDeparture))){22 MessageBox(hMainDlg, TEXT("请输入出发地!"), TEXT("提示"), MB_OK | MB_ICONINFORMATION);23 return FALSE;24 }25 else if (!(lstrlen(szDestination))){26 MessageBox(hMainDlg, TEXT("请输入目的地!"), TEXT("提示"), MB_OK | MB_ICONINFORMATION);27 return FALSE;28 }29 if (flag1 && !(lstrlen(szFltNum))){30 MessageBox(hMainDlg, TEXT("请输入出发地、目的地或航班号以查询航班!"), TEXT("提示"), MB_OK | MB_ICONINFORMATION);31 return FALSE;32 }33 34 p = flightlink.head;35 while (p){ //查找航班并输出36 if (flag1){ //按航班号查找37 if (!lstrcmp(p->Flight_Number, szFltNum) && !lstrcmp(p->Date,szDate)){ //查找到符合航班,输出38 if (!flag2){ //若该航班为第一班符合条件的航班39 _stprintf(szBuffer, TEXT("航班号\t出发地\t目的地\t起飞时间\t降落时间\t余座\t价格\t折扣\t出发日期\n"));40 SendMessage(hEdit, EM_SETSEL, LOWORD(-1), HIWORD(-1));41 SendMessage(hEdit, EM_REPLACESEL, 0, (LPARAM)(szBuffer));42 }//if43 flag2++;44 PrintFlight(hMainDlg, p); //输出航班信息45 }//if46 }//if47 else{ //按出发地、目的地查找48 if (!lstrcmp(p->Departure, szDeparture) && !lstrcmp(p->Destination, szDestination) && !lstrcmp(p->Date, szDate)){ //查找到符合航班,输出49 if (!flag2){ //若该航班为第一班符合条件的航班50 _stprintf(szBuffer, TEXT("航班号\t出发地\t目的地\t起飞时间\t降落时间\t余座\t价格\t折扣\t出发日期\n"));51 SendMessage(hEdit, EM_SETSEL, LOWORD(-1), HIWORD(-1));52 SendMessage(hEdit, EM_REPLACESEL, 0, (LPARAM)(szBuffer));53 }//if54 flag2++;55 PrintFlight(hMainDlg, p); //输出航班信息56 }//if57 }//else58 p = p->Next;59 }//while60 if (!flag2)61 MessageBox(hMainDlg, TEXT("对不起,没有符合您要求的航班"), TEXT("提示"), MB_OK | MB_ICONINFORMATION);62 return TRUE;63 }//SearchFlight()
1 //将所查航班信息输出 2 BOOL PrintFlight(HWND hwndDlg,Flight *p){ 3 TCHAR szBuffer[256]; 4 HWND hEdit = GetDlgItem(hwndDlg, IDC_INFORMATION); 5 6 _stprintf(szBuffer, TEXT("\n%s\t%s\t%s\t%s\t%s\t%d\t%.2lf\t%s\t%s\n\n"), 7 p->Flight_Number, //航班号 8 p->Departure, //出发地 9 p->Destination, //目的地10 p->TakeOff_Time, //起飞时间11 p->Landing_Time, //降落时间12 p->Vacant_Seat, //余座13 p->Fare, //价格14 p->Discount, //折扣15 p->Date); //出发日期16 17 SendMessage(hEdit, EM_SETSEL, LOWORD(-1), HIWORD(-1));18 SendMessage(hEdit, EM_REPLACESEL, 0, (LPARAM)(szBuffer)); 19 20 return TRUE;21 }
1 //订票 2 BOOL BookTickets(HWND hMainDlg){ 3 int tickets_num; 4 Flight *p; 5 TCHAR szFltNum[16], szDate[16]; 6 7 GetDlgItemText(hMainDlg, IDC_FLIGHTNUM, szFltNum, 15); //获取用户输入航班号 8 GetDlgItemText(hMainDlg, IDC_DATE, szDate, 15); //获取用户选择航班时间 9 10 if (!lstrlen(szFltNum)){11 MessageBox(hMainDlg, TEXT("请输入航班号以订票!"), TEXT("提示"), MB_OK | MB_ICONINFORMATION);12 return FALSE;13 }14 15 DialogBox(hInst, MAKEINTRESOURCE(IDD_FLTNUM), NULL, (DLGPROC)FlightNumDlgProc); //获取订票数目16 17 if (!lstrlen(szBuffer))18 return FALSE;19 20 tickets_num = _ttoi(szBuffer); //订票数目21 22 p = flightlink.head;23 while (p){ //查找航班并订票24 if (!lstrcmp(p->Flight_Number, szFltNum) && !lstrcmp(p->Date, szDate)) //查找到符合航班25 _Book_Tickets(hMainDlg,p,tickets_num);26 p = p->Next;27 }//while28 return TRUE;29 }//BookTickets() 30 31 32 //订票33 BOOL _Book_Tickets(HWND hwndDlg,Flight *p,int Tickets_Num){34 OrderForm *new_order = (OrderForm *)malloc(sizeof(OrderForm));35 if (!new_order){36 MessageBox(hwndDlg, TEXT("内存申请错误!"), TEXT("错误"), MB_OK | MB_ICONERROR);37 return FALSE;38 }39 40 if (Tickets_Num > p->Vacant_Seat){ //余票不足,给出建议航班41 Recommend(hwndDlg,p,Tickets_Num);42 return FALSE;43 }44 45 new_order->Order_Number = ++allorder.AllOrderNum; //新订单信息,总订单数+146 new_order->Tickets_Num = Tickets_Num;47 lstrcpy(new_order->IdNum, passenger->IdNum);48 lstrcpy(new_order->Flight_Number, p->Flight_Number);49 lstrcpy(new_order->Departure, p->Departure);50 lstrcpy(new_order->Destination, p->Destination);51 lstrcpy(new_order->Date, p->Date);52 lstrcpy(new_order->TakeOff_Time, p->TakeOff_Time);53 lstrcpy(new_order->Landing_Time, p->Landing_Time);54 new_order->Next = NULL;55 new_order->psgNext = NULL;56 57 if (allorder.head == NULL) //将结点添至订单链表末尾58 allorder.head = new_order;59 else60 allorder.tail->Next = new_order;61 allorder.tail = new_order;62 63 if (passenger->OrderLink.head == NULL) //将结点添至用户订单链表末尾64 passenger->OrderLink.head = new_order;65 else66 passenger->OrderLink.tail->psgNext = new_order;67 passenger->OrderLink.tail = new_order;68 passenger->OrderLink.OrderNum++;69 passenger->TicketNum += Tickets_Num;70 71 p->Vacant_Seat -= Tickets_Num; //航班余票-172 73 MessageBox(hwndDlg, TEXT("订票成功!"), TEXT("提示"), MB_OK | MB_ICONINFORMATION);74 75 return TRUE;76 }//_Book_Tickets()
1 //给出建议航班 2 BOOL Recommend(HWND hwndDlg, Flight *p,int Tickets_Num){ 3 SetDlgItemText(hwndDlg, IDC_INFORMATION, TEXT("\0")); //清空航班信息栏 4 5 int flag = 0; 6 TCHAR szBuffer[256] = {TEXT("\0")}; 7 HWND hEdit = GetDlgItem(hwndDlg, IDC_INFORMATION); 8 Flight *q; 9 10 q = flightlink.head;11 while (q){12 if (!(lstrcmp(p->Departure, q->Departure)) && 13 !(lstrcmp(p->Destination, q->Destination)) && 14 lstrcmp(p->Flight_Number, q->Flight_Number) && 15 Tickets_Num<=q->Vacant_Seat)16 {17 if (!flag){18 wsprintf(szBuffer, TEXT("您所订航班余票不足,以下为建议航班:\n"));19 SendMessage(hEdit, EM_SETSEL, LOWORD(-1), HIWORD(-1));20 SendMessage(hEdit, EM_REPLACESEL, 0, (LPARAM)(szBuffer));21 wsprintf(szBuffer, TEXT("\n"));22 SendMessage(hEdit, EM_SETSEL, LOWORD(-1), HIWORD(-1));23 SendMessage(hEdit, EM_REPLACESEL, 0, (LPARAM)(szBuffer));24 wsprintf(szBuffer, TEXT("航班号\t出发地\t目的地\t起飞时间\t降落时间\t余座\t价格\t折扣\t出发日期\n"));25 SendMessage(hEdit, EM_SETSEL, LOWORD(-1), HIWORD(-1));26 SendMessage(hEdit, EM_REPLACESEL, 0, (LPARAM)(szBuffer));27 ++flag;28 }//if29 PrintFlight(hwndDlg, q);30 }//if31 q = q->Next;32 }//while33 34 if (!flag){35 wsprintf(szBuffer, TEXT("对不起,您所订航班余票不足,当天也其它没有符合条件的航班...\n"));36 SendMessage(hEdit, EM_SETSEL, LOWORD(-1), HIWORD(-1));37 SendMessage(hEdit, EM_REPLACESEL, 0, (LPARAM)(szBuffer));38 }39 return TRUE;40 }//Recommend()
1 //退票 2 BOOL ReturnTickets(HWND hwndDlg){ 3 int flag = 0; 4 int num=0,tickets_num; 5 Flight *flight; 6 OrderForm *p,*q,*s,*prePoint; 7 TCHAR szFltNum[16], szDate[16]; 8 9 GetDlgItemText(hwndDlg, IDC_FLIGHTNUM, szFltNum, 15); //获取用户输入航班号 10 GetDlgItemText(hwndDlg, IDC_DATE, szDate, 15); //获取用户选择航班时间 11 12 if (!lstrlen(szFltNum)){ //未输入航班号 13 MessageBox(hwndDlg, TEXT("请输入航班号!"), TEXT("提示"), MB_OK | MB_ICONINFORMATION); 14 return FALSE; 15 } 16 17 DialogBox(hInst, MAKEINTRESOURCE(IDD_FLTNUM), NULL, (DLGPROC)FlightNumDlgProc); //获取退票数目 18 19 if (!lstrlen(szBuffer)) 20 return FALSE; 21 22 tickets_num = _ttoi(szBuffer); //退票数 23 24 p = passenger->OrderLink.head; 25 prePoint = p; 26 if (!p){ //用户无订单 27 MessageBox(hwndDlg, TEXT("当前用户没有已订票"), TEXT("提示"), MB_OK | MB_ICONINFORMATION); 28 return FALSE; 29 } 30 31 while (p){ //退票航班订票总数 32 if (!lstrcmp(p->Flight_Number, szFltNum) && !lstrcmp(p->Date, szDate)) 33 num += p->Tickets_Num; 34 p = p->psgNext; 35 } 36 if (tickets_num > num){ //退票数大于该航班已订票数 37 wsprintf(szBuffer, TEXT("对不起,该航班您只订了%d张机票,请重新填写退票张数"), num); 38 MessageBox(hwndDlg, szBuffer, TEXT("提示"), MB_OK | MB_ICONINFORMATION); 39 return FALSE; 40 }//if 41 42 p = passenger->OrderLink.head; 43 while (p){ //退票 44 if (!lstrcmp(p->Flight_Number, szFltNum) && !lstrcmp(p->Date, szDate) ){ 45 if (tickets_num >= p->Tickets_Num){ //当退票数大于等于当前订单内票数 46 47 s = p->psgNext; 48 passenger->TicketNum -= p->Tickets_Num; //用户订票数减少 49 allorder.AllOrderNum--; //总订单数减少 50 passenger->OrderLink.OrderNum--; //用户订单数减少 51 tickets_num -= p->Tickets_Num; //需要退票数减少 若需要退票数为0,则退出,否则继续循环 52 53 if (passenger->OrderLink.head == p){ //若p为头结点,删除头结点 54 passenger->OrderLink.head = p->psgNext; //头指针指向下一个结点 55 if (!p->psgNext) //若p同时为尾结点,则尾指针指向NULL 56 passenger->OrderLink.tail = NULL; 57 } 58 else if (!p->psgNext) //若p非头结点但为尾结点,尾指针指向前一个结点 59 passenger->OrderLink.tail = prePoint; 60 prePoint->psgNext = p->psgNext; //链表删除结点p 61 62 flight = flightlink.head; 63 while (flight){ //航班余座增加 64 if (!lstrcmp(flight->Flight_Number, szFltNum) && !lstrcmp(flight->Date, szDate)){ 65 flight->Vacant_Seat += p->Tickets_Num; 66 break; 67 } 68 flight = flight->Next; 69 }//while 70 71 q = allorder.head; 72 prePoint = q; 73 while (q){ //删除订单链表中订单结点 74 if (q == p){ //找到订单结点 75 if (allorder.head == p){ //若p为头结点,删除头结点 76 allorder.head = p->Next; //头指针指向下一个结点 77 if (!q->Next) //若q同时为尾结点,则尾指针指向NULL 78 allorder.tail = NULL; 79 } 80 else if (!q->Next) //若q非头结点但为尾结点,尾指针指向前一个结点 81 allorder.tail = prePoint; 82 prePoint->Next = q->Next; //链表删除结点q 83 free(p); break; //释放p结点内存 84 }//if 85 prePoint = q; 86 q = q->Next; 87 }//while 88 89 if (tickets_num){ //若退票数非0,则继续退票 90 p = s; continue; 91 } 92 93 MessageBox(hwndDlg, TEXT("退票成功!"), TEXT("提示"), MB_OK | MB_ICONINFORMATION); 94 return TRUE; 95 }//if 96 else{ //退票数小于该订单订票数 97 p->Tickets_Num -= tickets_num; //订单订票数减少 98 passenger->TicketNum -= tickets_num; //用户订票数减少 99 100 flight = flightlink.head;101 while (flight){ 102 if (!lstrcmp(flight->Flight_Number, szFltNum) && !lstrcmp(flight->Date, szDate)){103 flight->Vacant_Seat += tickets_num; //航班余票增加104 break;105 }106 flight = flight->Next;107 }//while108 109 MessageBox(hwndDlg, TEXT("退票成功!"), TEXT("提示"), MB_OK | MB_ICONINFORMATION);110 return TRUE; //退票成功111 }//else112 }//if113 prePoint = p;114 p = p->psgNext;115 }//while116 117 wsprintf(szBuffer, TEXT("对不起,您没有订该航班机票,请确认退票航班"));118 MessageBox(hwndDlg, szBuffer, TEXT("提示"), MB_OK | MB_ICONINFORMATION);119 return FALSE;120 }//ReturnTickets()
这篇文章就先到这里吧,其余功能的实现以及头文件、资源文件的代码在下篇文章中给出。