C语言如何拆分车主与车辆为两个独立关联的struct并实现增删查功能
C语言车辆管理系统改造实现
改造说明
完全匹配你的三个需求,同时修复了原代码的已知bug:
- 拆分两个独立结构体:
struct Owner存储车主姓名、年龄;struct Car存储关联车主姓名、车牌、车辆品牌,通过车主姓名做关联标识,逻辑简单易理解 - 单独封装
list_all_records()函数实现记录列出功能,按下选项2时调用,会完整打印车主和车辆的全部关联信息 - 内置最大容量为10的车辆数组,新增记录时会自动判断是否超出容量上限
- 修复原代码文件名不一致、车牌长度不足、
fflush(stdin)未定义行为等问题
完整代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> // 最大支持车辆数 #define MAX_CAR 10 // 字符串长度统一宏定义,方便修改 #define NAME_LEN 40 #define PLATE_LEN 10 #define BRAND_LEN 40 // 车主结构体 struct Owner { char name[NAME_LEN]; int age; }; // 车辆结构体,通过owner_name关联车主 struct Car { char owner_name[NAME_LEN]; char plate[PLATE_LEN]; char brand[BRAND_LEN]; // 内嵌车主结构体,直接存储关联的车主信息,方便查询 struct Owner owner; }; // 全局车辆数组,最多存10台 struct Car car_list[MAX_CAR]; // 已录入车辆计数 int car_count = 0; // 记录文件名称 const char *DATA_FILE = "car_records.dat"; /** * 独立函数:列出所有已登记的车辆+车主关联信息 */ void list_all_records() { system("clear"); if (car_count == 0) { printf("暂无登记记录\n"); return; } printf("=== 已登记车辆信息共%d条 ===\n", car_count); for (int i = 0; i < car_count; i++) { printf("\n第%d条记录:\n", i+1); printf("车主姓名:%s\n", car_list[i].owner.name); printf("车主年龄:%d\n", car_list[i].owner.age); printf("车辆品牌:%s\n", car_list[i].brand); printf("车牌号码:%s\n", car_list[i].plate); printf("---------------------------"); } } /** * 辅助函数:读取文件数据到车辆数组 */ void load_data_from_file(FILE *fp) { car_count = 0; rewind(fp); while (fread(&car_list[car_count], sizeof(struct Car), 1, fp) == 1 && car_count < MAX_CAR) { car_count++; } } /** * 辅助函数:将车辆数组数据写入文件 */ void save_data_to_file(FILE *fp) { rewind(fp); ftruncate(fileno(fp), 0); // 清空文件原有内容 for (int i = 0; i < car_count; i++) { fwrite(&car_list[i], sizeof(struct Car), 1, fp); } fflush(fp); } int main() { FILE *fp; char another, choice; char del_name[NAME_LEN]; // 清空换行符用的临时变量 int tmp; // 打开数据文件 fp = fopen(DATA_FILE, "rb+"); if (fp == NULL) { fp = fopen(DATA_FILE, "wb+"); if (fp == NULL) { printf("无法打开数据文件\n"); exit(1); } } // 启动时先加载已有数据到数组 load_data_from_file(fp); while (1) { system("clear"); printf("\n===== 车辆管理系统 =====\n"); printf("1. 新增记录\n"); printf("2. 列出所有记录\n"); printf("3. 删除记录\n"); printf("4. 退出\n"); printf("请输入你的选择:"); choice = getchar(); // 吞掉输入后的换行符 while ((tmp = getchar()) != '\n' && tmp != EOF); switch(choice) { case '1': system("clear"); if (car_count >= MAX_CAR) { printf("已达到最大10台车辆的存储上限,无法新增\n"); printf("按回车键返回主菜单\n"); getchar(); break; } another = 'y'; while (another == 'y' && car_count < MAX_CAR) { struct Car new_car; printf("请输入车主姓名:"); scanf("%s", new_car.owner.name); printf("请输入车主年龄:"); scanf("%d", &new_car.owner.age); // 同步关联的车主名称到车辆结构体 strcpy(new_car.owner_name, new_car.owner.name); printf("请输入车辆品牌:"); scanf("%s", new_car.brand); printf("请输入车牌号码:"); scanf("%s", new_car.plate); // 加入数组 car_list[car_count] = new_car; car_count++; // 写入文件 save_data_to_file(fp); printf("\n是否要新增另一条记录(y/n):"); // 吞掉换行 while ((tmp = getchar()) != '\n' && tmp != EOF); another = getchar(); while ((tmp = getchar()) != '\n' && tmp != EOF); } if (car_count >= MAX_CAR) { printf("已达到最大10台车辆的存储上限\n"); printf("按回车键返回主菜单\n"); getchar(); } break; case '2': list_all_records(); printf("\n按回车键返回主菜单\n"); getchar(); break; case '3': system("clear"); another = 'y'; while (another == 'y') { printf("请输入要删除的车主姓名:"); scanf("%s", del_name); // 找到对应记录删除 int found = 0; for (int i = 0; i < car_count; i++) { if (strcmp(car_list[i].owner.name, del_name) == 0) { // 后面的元素前移覆盖 for (int j = i; j < car_count - 1; j++) { car_list[j] = car_list[j+1]; } car_count--; found = 1; i--; // 处理同名的多条记录 } } if (found) { save_data_to_file(fp); printf("删除成功\n"); } else { printf("未找到对应车主的记录\n"); } printf("\n是否要删除另一条记录(y/n):"); while ((tmp = getchar()) != '\n' && tmp != EOF); another = getchar(); while ((tmp = getchar()) != '\n' && tmp != EOF); } break; case '4': fclose(fp); printf("退出程序\n"); exit(0); default: printf("输入无效,请输入1-4的数字\n"); printf("按回车键返回主菜单\n"); getchar(); } } return 0; }
使用说明
- 编译命令:
gcc car_manage.c -o car_manage - 运行后按菜单提示操作即可,所有数据会自动持久化到
car_records.dat文件中,重启程序不会丢失
内容的提问来源于stack exchange,提问作者Masih MK
相关产品推荐
相关产品推荐

