C语言飞机订票系统课程设计
项目概述与需求分析
项目目标 设计并实现一个基于控制台的飞机订票系统,该系统应能够模拟航空公司的订票业务,包括航班信息的录入、查询、订票、退票以及信息保存与加载等核心功能,通过本课程设计,旨在巩固和运用C语言的核心知识,如结构体、文件操作、指针、函数模块化编程等。

(图片来源网络,侵删)
功能需求分析
系统主要面向两类用户:管理员和普通乘客(系统内部通过菜单切换模拟)。
A. 管理员功能
- 航班信息录入:可以添加新的航班信息,包括航班号、起点站、终点站、日期、时间、总座位数、已订票数、票价等。
- 航班信息浏览:以表格形式列出所有航班的详细信息。
- 航班信息查询:可以根据航班号或航线(起点-终点)查询特定航班。
- 航班信息修改:修改指定航班的某些信息(如票价、总座位数)。
- 航班信息删除:删除某个已取消的航班。
B. 乘客功能

(图片来源网络,侵删)
- 航班查询:乘客可以根据航线(起点-终点)和日期查询所有符合条件的航班。
- 订票功能:在查询结果中选择一个航班进行订票,系统需要检查是否有余票,并更新订票信息。
- 退票功能:乘客可以根据自己的姓名和身份证号(或航班号)查询已订的机票并进行退票,释放座位。
- 个人信息查询:查询自己已预订的航班信息。
C. 公共/核心功能
- 数据持久化:所有航班信息和订票信息必须保存在文件中(如
flights.dat和bookings.dat),确保程序关闭后数据不丢失,程序启动时能自动从文件中加载数据。 - 菜单驱动界面:提供清晰、友好的文本用户界面,引导用户进行操作。
系统设计
数据结构设计
为了高效地管理数据,我们使用结构体来定义核心数据对象。
-
航班信息结构体 (
Flight)
(图片来源网络,侵删)typedef struct { char flight_id[20]; // 航班号, 如 "CA1234" char origin[20]; // 起点站 char destination[20]; // 终点站 char date[20]; // 日期, 如 "2025-12-25" char time[20]; // 时间, 如 "08:00" int total_seats; // 总座位数 int booked_seats; // 已订票数 float price; // 票价 } Flight; -
订票信息结构体 (
Booking) 为了方便退票和个人查询,需要一个结构体来记录谁订了哪个票。typedef struct { char flight_id[20]; // 关联的航班号 char passenger_name[50]; // 乘客姓名 char id_card[19]; // 乘客身份证号 } Booking;
功能模块设计
将整个系统划分为多个独立的函数模块,提高代码的可读性和可维护性。
| 模块名称 | 主要功能 |
|---|---|
| 主菜单模块 | (main函数) 显示主菜单,处理管理员/乘客选择,调用相应模块。 |
| 管理员模块 | (admin_menu) 显示管理员子菜单,并调用航班管理的增删改查函数。 |
| 乘客模块 | (passenger_menu) 显示乘客子菜单,并调用查询、订票、退票函数。 |
| 航班管理模块 | add_flight(), list_flights(), search_flight(), modify_flight(), delete_flight() |
| 订票业务模块 | search_flights_for_booking(), book_ticket(), cancel_ticket(), my_bookings() |
| 文件操作模块 | save_flights(), load_flights(), save_bookings(), load_bookings() |
| 工具模块 | clear_input_buffer(), get_input() (用于安全输入) |
文件设计
flights.dat:二进制文件,用于存储所有Flight结构体数组。bookings.dat:二进制文件,用于存储所有Booking结构体数组。
使用二进制文件进行读写,效率高,且能直接保存结构体数据。
核心代码实现
以下是一个完整可运行的源代码示例,你可以直接复制到你的IDE(如 Dev-C++, VS Code, Code::Blocks)中编译运行。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h> // 用于 getch(),实现不回显的输入
// 定义常量
#define MAX_FLIGHTS 100
#define MAX_BOOKINGS 1000
#define FLIGHTS_FILE "flights.dat"
#define BOOKINGS_FILE "bookings.dat"
// --- 数据结构定义 ---
typedef struct {
char flight_id[20];
char origin[20];
char destination[20];
char date[20];
char time[20];
int total_seats;
int booked_seats;
float price;
} Flight;
typedef struct {
char flight_id[20];
char passenger_name[50];
char id_card[19];
} Booking;
// --- 全局变量 ---
Flight flights[MAX_FLIGHTS];
Booking bookings[MAX_BOOKINGS];
int flight_count = 0;
int booking_count = 0;
// --- 函数声明 ---
void admin_menu();
void passenger_menu();
void load_data();
void save_data();
// --- 管理员功能函数 ---
void add_flight();
void list_flights();
void search_flight();
void modify_flight();
void delete_flight();
// --- 乘客功能函数 ---
void search_flights_for_booking();
void book_ticket();
void cancel_ticket();
void my_bookings();
// --- 工具函数 ---
void clear_input_buffer();
void press_any_key_to_continue();
// --- 主函数 ---
int main() {
load_data(); // 程序启动时加载数据
int choice;
while (1) {
system("cls"); // 清屏 (Windows), Linux/macOS 用 "clear"
printf("\n\n\t\t\t 飞机订票系统\n");
printf("\n\t\t\t 1. 管理员入口");
printf("\n\t\t\t 2. 乘客入口");
printf("\n\t\t\t 0. 退出系统");
printf("\n\n\t\t\t 请选择您的身份: ");
scanf("%d", &choice);
clear_input_buffer();
switch (choice) {
case 1:
admin_menu();
break;
case 2:
passenger_menu();
break;
case 0:
save_data(); // 退出前保存数据
printf("\n\t\t\t 感谢使用,再见!\n");
exit(0);
default:
printf("\n\t\t\t 无效输入,请重新选择!");
press_any_key_to_continue();
}
}
return 0;
}
// --- 文件操作函数 ---
void load_data() {
FILE *fp_flights = fopen(FLIGHTS_FILE, "rb");
if (fp_flights) {
fread(&flight_count, sizeof(int), 1, fp_flights);
fread(flights, sizeof(Flight), flight_count, fp_flights);
fclose(fp_flights);
}
FILE *fp_bookings = fopen(BOOKINGS_FILE, "rb");
if (fp_bookings) {
fread(&booking_count, sizeof(int), 1, fp_bookings);
fread(bookings, sizeof(Booking), booking_count, fp_bookings);
fclose(fp_bookings);
}
}
void save_data() {
FILE *fp_flights = fopen(FLIGHTS_FILE, "wb");
if (fp_flights) {
fwrite(&flight_count, sizeof(int), 1, fp_flights);
fwrite(flights, sizeof(Flight), flight_count, fp_flights);
fclose(fp_flights);
}
FILE *fp_bookings = fopen(BOOKINGS_FILE, "wb");
if (fp_bookings) {
fwrite(&booking_count, sizeof(int), 1, fp_bookings);
fwrite(bookings, sizeof(Booking), booking_count, fp_bookings);
fclose(fp_bookings);
}
}
// --- 管理员菜单和功能 ---
void admin_menu() {
int choice;
while (1) {
system("cls");
printf("\n\n\t\t\t 管理员菜单\n");
printf("\n\t\t\t 1. 添加航班");
printf("\n\t\t\t 2. 浏览所有航班");
printf("\n\t\t\t 3. 查询航班");
printf("\n\t\t\t 4. 修改航班");
printf("\n\t\t\t 5. 删除航班");
printf("\n\t\t\t 0. 返回主菜单");
printf("\n\n\t\t\t 请选择: ");
scanf("%d", &choice);
clear_input_buffer();
switch (choice) {
case 1: add_flight(); break;
case 2: list_flights(); break;
case 3: search_flight(); break;
case 4: modify_flight(); break;
case 5: delete_flight(); break;
case 0: return;
default: printf("\n\t\t\t 无效输入!"); press_any_key_to_continue();
}
}
}
void add_flight() {
if (flight_count >= MAX_FLIGHTS) {
printf("\n\t\t\t 航班数量已达上限,无法添加!\n");
press_any_key_to_continue();
return;
}
Flight f;
printf("\n\t\t\t 请输入航班号: "); gets(f.flight_id);
printf("\t\t\t 请输入起点站: "); gets(f.origin);
printf("\t\t\t 请输入终点站: "); gets(f.destination);
printf("\t\t\t 请输入日期 (YYYY-MM-DD): "); gets(f.date);
printf("\t\t\t 请输入时间 (HH:MM): "); gets(f.time);
printf("\t\t\t 请输入总座位数: "); scanf("%d", &f.total_seats);
printf("\t\t\t 请输入票价: "); scanf("%f", &f.price);
clear_input_buffer();
f.booked_seats = 0;
flights[flight_count++] = f;
printf("\n\t\t\t 航班添加成功!\n");
press_any_key_to_continue();
}
void list_flights() {
if (flight_count == 0) {
printf("\n\t\t\t 当前没有航班信息!\n");
press_any_key_to_continue();
return;
}
printf("\n%-15s %-10s %-10s %-12s %-8s %-10s %-10s %s\n",
"航班号", "起点", "终点", "日期", "时间", "总座位", "已订", "票价");
printf("--------------------------------------------------------------------------------\n");
for (int i = 0; i < flight_count; i++) {
printf("%-15s %-10s %-10s %-12s %-8s %-10d %-10d %.2f\n",
flights[i].flight_id, flights[i].origin, flights[i].destination,
flights[i].date, flights[i].time, flights[i].total_seats,
flights[i].booked_seats, flights[i].price);
}
press_any_key_to_continue();
}
// ... (其他管理员函数 search_flight, modify_flight, delete_flight 的实现逻辑类似)
// search_flight: 遍历数组,按航班号或航线查找并显示。
// modify_flight: 按航班号查找,然后允许用户修改除航班号外的其他信息。
// delete_flight: 按航班号查找,找到后将其后所有元素前移,flight_count--。
// --- 乘客菜单和功能 ---
void passenger_menu() {
int choice;
while (1) {
system("cls");
printf("\n\n\t\t\t 乘客菜单\n");
printf("\n\t\t\t 1. 查询航班");
printf("\n\t\t\t 2. 订票");
printf("\n\t\t\t 3. 退票");
printf("\n\t\t\t 4. 我的订单");
printf("\n\t\t\t 0. 返回主菜单");
printf("\n\n\t\t\t 请选择: ");
scanf("%d", &choice);
clear_input_buffer();
switch (choice) {
case 1: search_flights_for_booking(); break;
case 2: book_ticket(); break;
case 3: cancel_ticket(); break;
case 4: my_bookings(); break;
case 0: return;
default: printf("\n\t\t\t 无效输入!"); press_any_key_to_continue();
}
}
}
void search_flights_for_booking() {
char origin[20], destination[20], date[20];
printf("\n\t\t\t 请输入起点站: "); gets(origin);
printf("\t\t\t 请输入终点站: "); gets(destination);
printf("\t\t\t 请输入日期 (YYYY-MM-DD): "); gets(date);
printf("\n%-15s %-10s %-10s %-12s %-8s %-10s %-10s %s\n",
"航班号", "起点", "终点", "日期", "时间", "总座位", "已订", "票价");
printf("--------------------------------------------------------------------------------\n");
int found = 0;
for (int i = 0; i < flight_count; i++) {
if (strcmp(flights[i].origin, origin) == 0 &&
strcmp(flights[i].destination, destination) == 0 &&
strcmp(flights[i].date, date) == 0) {
printf("%-15s %-10s %-10s %-12s %-8s %-10d %-10d %.2f\n",
flights[i].flight_id, flights[i].origin, flights[i].destination,
flights[i].date, flights[i].time, flights[i].total_seats,
flights[i].booked_seats, flights[i].price);
found = 1;
}
}
if (!found) {
printf("\n\t\t\t 未找到符合条件的航班!\n");
}
press_any_key_to_continue();
}
void book_ticket() {
char flight_id[20];
printf("\n\t\t\t 请输入您要预订的航班号: "); gets(flight_id);
int flight_index = -1;
for (int i = 0; i < flight_count; i++) {
if (strcmp(flights[i].flight_id, flight_id) == 0) {
flight_index = i;
break;
}
}
if (flight_index == -1) {
printf("\n\t\t\t 错误:未找到该航班!\n");
press_any_key_to_continue();
return;
}
if (flights[flight_index].booked_seats >= flights[flight_index].total_seats) {
printf("\n\t\t\t 抱歉,该航班已满座!\n");
press_any_key_to_continue();
return;
}
Booking b;
strcpy(b.flight_id, flight_id);
printf("\n\t\t\t 请输入您的姓名: "); gets(b.passenger_name);
printf("\t\t\t 请输入您的身份证号: "); gets(b.id_card);
bookings[booking_count++] = b;
flights[flight_index].booked_seats++;
printf("\n\t\t\t 订票成功!祝您旅途愉快!\n");
press_any_key_to_continue();
}
void cancel_ticket() {
char id_card[19];
printf("\n\t\t\t 请输入您的身份证号以查找订单: "); gets(id_card);
int booking_index = -1;
for (int i = 0; i < booking_count; i++) {
if (strcmp(bookings[i].id_card, id_card) == 0) {
booking_index = i;
break;
}
}
if (booking_index == -1) {
printf("\n\t\t\t 未找到您的订票记录!\n");
press_any_key_to_continue();
return;
}
// 找到订单,开始退票
char flight_id_to_cancel[20];
strcpy(flight_id_to_cancel, bookings[booking_index].flight_id);
// 1. 从订票记录中删除
for (int i = booking_index; i < booking_count - 1; i++) {
bookings[i] = bookings[i + 1];
}
booking_count--;
// 2. 更新航班的已订票数
for (int i = 0; i < flight_count; i++) {
if (strcmp(flights[i].flight_id, flight_id_to_cancel) == 0) {
flights[i].booked_seats--;
break;
}
}
printf("\n\t\t\t 退票成功!\n");
press_any_key_to_continue();
}
void my_bookings() {
char id_card[19];
printf("\n\t\t\t 请输入您的身份证号: "); gets(id_card);
printf("\n%-15s %-20s %-19s\n", "航班号", "乘客姓名", "身份证号");
printf("------------------------------------------------\n");
int found = 0;
for (int i = 0; i < booking_count; i++) {
if (strcmp(bookings[i].id_card, id_card) == 0) {
printf("%-15s %-20s %-19s\n",
bookings[i].flight_id, bookings[i].passenger_name, bookings[i].id_card);
found = 1;
}
}
if (!found) {
printf("\n\t\t\t 未找到您的订票记录!\n");
}
press_any_key_to_continue();
}
// --- 工具函数实现 ---
void clear_input_buffer() {
while (getchar() != '\n');
}
void press_any_key_to_continue() {
printf("\n\n\t\t\t 按任意键继续...");
getch();
}
系统测试与运行指南
- 编译运行:将以上代码保存为
ticket_system.c,使用C语言编译器(如gcc ticket_system.c -o ticket_system)进行编译,然后运行生成的可执行文件。 - 管理员操作:
- 选择
1进入管理员菜单。 - 选择
1添加几个示例航班,- 航班号:
MU5101, 起点:北京, 终点:上海, 日期:2025-12-25, 时间:09:00, 总座位:150, 票价:1200 - 航班号:
CZ3102, 起点:广州, 终点:成都, 日期:2025-12-25, 时间:14:30, 总座位:180, 票价:900
- 航班号:
- 选择
2浏览所有航班,检查添加是否成功。 - 选择
0返回主菜单。
- 选择
- 乘客操作:
- 选择
2进入乘客菜单。 - 选择
1查询航班,输入起点北京,终点上海,日期2025-12-25,应能看到刚才添加的MU5101航班。 - 选择
2订票,输入航班号MU5101,然后输入一个假姓名和身份证号(如张三,110101199001011234)。 - 再次选择
1查询航班,会发现MU5101的已订票数增加了。 - 选择
4我的订单,输入身份证号110101199001011234,应能看到自己的订票记录。 - 选择
3退票,输入身份证号110101199001011234,成功退票后,再次查询MU5101,已订票数会减少。
- 选择
- 数据持久化测试:
- 完成上述操作后,直接关闭程序。
- 重新打开程序,你会发现之前添加的航班和订票记录都还在,这说明数据保存和加载功能正常工作。
项目扩展与优化建议
如果想让你的课程设计更出彩,可以考虑以下扩展方向:
- 用户账户系统:为乘客和管理员增加用户名和密码,而不是通过菜单选择身份,密码需要加密存储(如使用简单的异或加密或调用更安全的库)。
- 更复杂的查询:增加按价格范围、起飞时间范围等条件进行查询。
- 数据结构优化:使用链表代替数组来存储航班和订票信息,这样可以动态分配内存,避免数组大小限制,插入和删除也更高效。
- 图形用户界面:如果学过相关库(如 EasyX for Windows, GTK for Linux),可以尝试将文本界面升级为图形界面,提升用户体验。
- 排序功能:在浏览航班列表时,可以增加按起飞时间、票价等字段进行排序的功能。
- 航班状态管理:增加“已起飞”、“已到达”、“已取消”等状态,并据此控制订票和退票。
- 多线程/并发:这是一个高阶扩展,可以模拟多个用户同时订票的场景,使用多线程来处理,并引入锁机制来防止“超卖”问题(即多个线程同时检查到有票,同时进行订票操作,导致实际票数不够)。
这个项目涵盖了C语言课程设计的绝大部分核心知识点,是一个非常好的练习,祝你顺利完成!
