C语言飞机座位预订系统:如何将座位与乘客信息写入txt文件
C语言飞机座位预订程序修复与实现方案
现存代码的直接问题(多数是导致程序崩溃的根源)
- 数组越界:
struct Airplane中seats数组仅定义了6个元素,但初始化、预订逻辑均按10排座位设计,访问超出数组长度的内存会直接触发程序崩溃;struct Seats内的seats数组长度写为10,实际每排仅6个座位(A-F),也存在内存浪费和越界风险 - 状态不共享:
book()函数内部重新定义并初始化了独立的Airplane变量,和main函数中维护的全局座位状态完全隔离,每次调用book都会重置所有座位为空闲,之前的预订记录直接丢失 - 输入逻辑错误:多处
scanf调用漏传地址符&,读取居住城市时错用整数格式符%d,会非法写内存导致程序中途退出;使用fflush(stdin)属于C标准未定义行为,在部分编译器下无法清空输入缓冲区,会导致输入项被残留换行符跳过 - 文件操作错误:用
"w"模式打开存储文件每次都会清空全部历史记录,且打开文件后没有执行任何写入操作,根本无法持久化保存乘客数据 - 数据无关联:
Passenger结构体未存储座位信息,无法把乘客和他订的座位绑定,自然没法实现记录查询、改签、删除功能
必要的结构体修改
先修正结构体定义,补充座位关联字段,固定数组长度避免越界:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #define MAX_ROWS 10 // 总排数10 #define MAX_COLS 6 // 每排6座 A-F #define MAX_STR_LEN 50 // 姓名、城市最大长度 #define DATA_FILE "Passengers.txt" struct Passenger{ int pnum; int age; char city[MAX_STR_LEN]; char name[MAX_STR_LEN]; int seat_row; // 新增:绑定座位排号 1~10 char seat_col; // 新增:绑定座位列号 A~F }; struct Seats{ int row; char seats[MAX_COLS]; // 修正长度为每排6座 }; struct Airplane{ struct Seats seats[MAX_ROWS]; // 修正长度为总排数10 int booked_count; // 全局统计已预订座位数,不用每次遍历计算 };
修正初始化函数,匹配数组长度,程序启动时先加载历史文件恢复座位状态:
// 清空输入缓冲区的工具函数,替代未定义的fflush(stdin) void clear_input_buffer() { int c; while((c = getchar()) != '\n' && c != EOF); } void initializeDefault(struct Airplane *airplane){ airplane->booked_count = 0; for(int i=0;i<MAX_ROWS;i++){ airplane->seats[i].row = i+1; for(int j=0;j<MAX_COLS;j++){ airplane->seats[i].seats[j] = 'A' + j; // 空闲座位存原字符,预订后改为'X' } } // 启动时加载历史预订记录,恢复座位状态 FILE *fp = fopen(DATA_FILE, "r"); if(fp == NULL) return; // 第一次运行无文件直接返回 struct Passenger tmp; while(fscanf(fp, "%d %49s %d %49s %d %c", &tmp.pnum, tmp.name, &tmp.age, tmp.city, &tmp.seat_row, &tmp.seat_col) == 6) { int r = tmp.seat_row - 1; int c = toupper(tmp.seat_col) - 'A'; if(r >=0 && r < MAX_ROWS && c >=0 && c < MAX_COLS && airplane->seats[r].seats[c] != 'X') { airplane->seats[r].seats[c] = 'X'; airplane->booked_count++; } } fclose(fp); }
book()函数实现逻辑
所有座位操作函数都要传入main中维护的Airplane指针,保证全局状态一致;预订成功后同步把乘客+绑定的座位信息写入文件:
// 注意传入Airplane指针,共享全局座位状态 void book(struct Airplane *airplane){ if(airplane->booked_count == MAX_ROWS * MAX_COLS) { printf("\nAll seats are booked now.\n"); return; } int n, i; printf("How many passengers/seats you want to reserve?: "); scanf("%d", &n); clear_input_buffer(); struct Passenger *p = (struct Passenger*)malloc(n * sizeof(struct Passenger)); // 追加模式打开文件,新预订记录追加到末尾,不会清空历史 FILE *fp = fopen(DATA_FILE, "a"); if(fp == NULL) { printf("Failed to open data file.\n"); free(p); return; } for(i=0;i<n;i++){ if(airplane->booked_count >= MAX_ROWS * MAX_COLS) { printf("No enough available seats, stop booking.\n"); break; } printf("Enter passenger ID: "); scanf("%d", &p[i].pnum); // 注意加&传地址 clear_input_buffer(); printf("Enter #%d passenger's name: ", i+1); scanf("%49[^\n]", p[i].name); // 限制长度避免缓冲区溢出 clear_input_buffer(); printf("What's the passenger's age?: "); scanf("%d", &p[i].age); clear_input_buffer(); printf("Please enter the city where the passenger resides: "); scanf("%49[^\n]", p[i].city); clear_input_buffer(); int row, valid = 0; char col; do { printf("\nEnter Seat row (1-10): "); scanf("%d", &row); clear_input_buffer(); printf("Enter Seat column (A-F): "); scanf("%c", &col); col = toupper(col); // 自动转大写,支持用户输入小写a-f clear_input_buffer(); if(row <1 || row > MAX_ROWS || col <'A' || col > 'F') { printf("Invalid seat number, please re-enter.\n"); continue; } if(airplane->seats[row-1].seats[col-'A'] == 'X') { printf("Seat %d%c is already booked, please choose another.\n", row, col); continue; } valid = 1; } while(!valid); // 标记座位为已预订 airplane->seats[row-1].seats[col-'A'] = 'X'; airplane->booked_count++; // 把座位信息绑定到乘客结构体 p[i].seat_row = row; p[i].seat_col = col; // 同步写入文件 fprintf(fp, "%d %s %d %s %d %c\n", p[i].pnum, p[i].name, p[i].age, p[i].city, p[i].seat_row, p[i].seat_col); printf("Seat %d%c is booked successfully.\n\n", row, col); } fclose(fp); free(p); }
其余功能实现提示
- 座位展示(功能2):直接遍历Airplane的seats数组,每排遍历6个座位,如果字符是'X'就显示X,否则显示原座位字符(A-F)即可
- 预订记录展示(功能5):逐行读取
Passengers.txt,按写入时的格式解析出Passenger结构体的所有字段,格式化输出姓名、年龄、城市、座位号即可 - 改签、删除功能:操作时先更新Airplane中对应座位的状态,再把文件中所有有效记录重新写入(删除旧记录、写入更新后的记录),保证文件和内存状态一致
- main函数中调用book时,需要传入airplane的地址:
case 1: book(&airplane); break;,其余功能函数如果要操作座位状态,也需要传入这个指针
内容的提问来源于stack exchange,提问作者Valentine
相关产品推荐
相关产品推荐

