作者简介Nebula嵌入式 | 嵌入式软件工程师技术背景22届普通二本院校毕业生专注于嵌入式软件开发MCU/RTOS/Linux应用/Linux驱动开发 持续学习中内容创作小红书、抖音、B站同名账号分享嵌入式知识和日常工作欢迎关注商务合作/需要学习资料联系️nebula0419备注商务合作/学习资料修订记录版本修改时间修改内容1.02023.3.18初稿Linux 下通讯录练习项目2.02024.6.7修正导入/删除逻辑与输入边界3.02026.7.30去掉 fflush(stdin)为 scanf 增加宽度限制4.02026.8.1梳理通讯录模块划分与结构体数组模型补强表驱动菜单、删除重排、导入导出与输入边界要点一、前言本文实现一个简易通讯录管理系统基于 Linux清屏使用clear。项目把前面学过的结构体数组、函数指针表驱动和文件 IO串成一条可运行链路内存里维护联系人磁盘用contact_data.txt做导入导出。耗时约三小时难免有边界可继续打磨欢迎留言指出。二、总体设计与功能总览读图要点核心能力添加、删除、搜索、修改、显示全部以及导入/导出持久化。容量上限PEOPLE_NUM100可后续改为动态开辟退出通过菜单项调用exit。功能清单保存最多 100 人信息后续可优化成动态开辟。增加人的信息。删除指定联系人的信息。查询指定联系人的信息。修改指定联系人的信息。显示所有联系人的信息。导入导出通讯录。人的信息字段名字、年龄、性别、电话、地址。知识点结构体数组、函数指针回调、文件操作函数。三、数据模型结构体与数组读图要点PEOPLE_INFO描述单条记录addr_people[PEOPLE_NUM]是固定容量池。有效人数用arr_num维护空槽以serial_num -1标记初始化时全部置 -1。typedef struct { int serial_num; char name[20]; int age; char sex[5]; char phone[15]; char addr[20]; } PEOPLE_INFO; PEOPLE_INFO addr_people[PEOPLE_NUM]; int arr_num 0; /* 通讯录人数 */四、菜单表驱动函数指针读图要点MENU_LIST把「菜单文字」与「函数指针」绑定末尾{NULL, NULL}作哨兵。用户输入num后执行menu[num - 1].Function()避免冗长switch扩展时只加表项。typedef struct { char *func_str; int (*Function)(void); } MENU_LIST; MENU_LIST menu[] { {退出系统, Exitsys}, {添加, AddContact}, {删除, DelContact}, {搜索, SearchContact}, {修改, ModifyContact}, {显示所有联系人, ShowContact}, {导入, ImportContact}, {导出, ExportContact}, {NULL, NULL} };五、添加与容量检查读图要点添加前先判arr_num PEOPLE_NUM满员直接返回防止写越界。字段用带宽度的scanf如%19s、%14s写入后arr_numserial_num arr_num 1写入当下槽位时用当前下标 1。六、删除移位与序号重排读图要点按序号定位后后续元素整体前移覆盖空洞再arr_num--。删除后必须重排serial_num i 1并把尾槽置serial_num -1保证序号连续、遍历可停。七、三种搜索模式读图要点搜索入口再分子菜单序号 / 名字 / 电话分别线性扫描匹配。名字、电话用strcmp命中打印整行未命中给出明确提示。修改功能按序号定位后对 name/age/sex/phone/addr 五项依次询问输入n可跳过该项。八、导入导出与文件 IO读图要点导出fprintf按行写出到同级目录contact_data.txt导入fgetssscanf解析回数组。导入开头必须arr_num 0否则重复导入会累加甚至越界。文本行格式示例num 1 name Zhang age 25 sex M phone 13800000000 addr Beijing九、主循环与输入边界读图要点InitContact后进入while(1)显示菜单 → 读选项 → 清屏 → 回调对应函数。输入侧带宽度scanf、非法输入时吞掉残留字符不要用不可移植的fflush(stdin)clear依赖 LinuxWindows 可改为cls或条件编译。十、完整代码#include stdio.h #include stdlib.h #include string.h int Exitsys(); int InitContact(); int AddContact(); int DelContact(); int SearchContact(); int ModifyContact(); int ShowContact(); int SortContact(); int ImportContact(); int ExportContact(); #define MENU_LEN 10 #define PEOPLE_NUM 100 typedef struct { int serial_num; char name[20]; int age; char sex[5]; char phone[15]; char addr[20]; } PEOPLE_INFO; typedef struct { char *func_str; int (*Function)(void); } MENU_LIST; PEOPLE_INFO addr_people[PEOPLE_NUM]; int arr_num 0;//通讯录人数 MENU_LIST menu[] { {退出系统, Exitsys}, // 退出系统 {添加, AddContact}, // 添加 {删除, DelContact}, // 删除 {搜索, SearchContact}, // 搜索 {修改, ModifyContact}, // 修改 {显示所有联系人, ShowContact}, // 显示所有联系人 //{排序, SortContact}, // 排序 {导入, ImportContact}, // 导入 {导出, ExportContact}, // 导出 {NULL, NULL} }; int Exitsys() { exit(0); return 0; } int InitContact() { /* init arr */ int i; for(i 0;i PEOPLE_NUM; i) { addr_people[i].serial_num -1; } return 0; } /* 添加用户 */ int AddContact() { if (arr_num PEOPLE_NUM) { printf(通讯录已满(%d)无法继续添加!\n, PEOPLE_NUM); return -1; } char user_name[20] {0}; int user_age 0; char user_sex[5] {0}; char user_phone[15] {0}; char user_addr[20] {0}; printf(开始添加联系人!\n); printf(请输入联系人的姓名); scanf(%19s, user_name); printf(请输入联系人的年龄); scanf(%d, user_age); printf(请输入联系人的性别); scanf(%4s, user_sex); printf(请输入联系人的电话); scanf(%14s, user_phone); printf(请输入联系人的地址); scanf(%19s, user_addr); addr_people[arr_num].serial_num arr_num 1; strcpy(addr_people[arr_num].name, user_name); addr_people[arr_num].age user_age; strcpy(addr_people[arr_num].sex, user_sex); strcpy(addr_people[arr_num].phone, user_phone); strcpy(addr_people[arr_num].addr, user_addr); printf(用户 %s 添加成功\n, user_name); arr_num; return 0; } int DelContact() { int num; int people_num_status ShowContact(); if(people_num_status -1) { printf(通讯录列表为空,无法进行修改操作...); return -1; } printf(请输入你要删除的联系人的序号(1-%d):, arr_num); if (scanf(%d, num) ! 1 || num 1 || num arr_num) { printf(输入错误!\n); return -1; } num--; int i; for (i num; i arr_num - 1; i) { addr_people[i] addr_people[i 1]; } arr_num--; if (arr_num 0 arr_num PEOPLE_NUM) addr_people[arr_num].serial_num -1; for (i 0; i arr_num; i) addr_people[i].serial_num i 1; return 0; } int num_find() { int serial_num; system(clear); printf(请输入你要查找的序号:); scanf(%d, serial_num); int i 0; int find_flag 0; while(addr_people[i].serial_num ! -1) { if(addr_people[i].serial_num serial_num) { find_flag 1; break; } i; } if(find_flag 1) { system(clear); printf(查找结束...\n); printf(num:%-3d|name:%-10s|age:%-2d|sex:%-3s|phone:%-15s|addr:%-10s\n, addr_people[i].serial_num, addr_people[i].name, addr_people[i].age, addr_people[i].sex, addr_people[i].phone, addr_people[i].addr); }else { system(clear); printf(查找结束,未查找到相关信息...\n); } return 0; } int name_find() { char user_name[20] {0}; system(clear); printf(请输入你要查找的用户名:); scanf(%19s, user_name); int i 0; int find_flag 0; while(addr_people[i].serial_num ! -1) { if(!strcmp(addr_people[i].name, user_name)) { find_flag 1; break; } i; } if(find_flag 1) { system(clear); printf(查找结束...\n); printf(num:%-3d|name:%-10s|age:%-2d|sex:%-3s|phone:%-15s|addr:%-10s\n, addr_people[i].serial_num, addr_people[i].name, addr_people[i].age, addr_people[i].sex, addr_people[i].phone, addr_people[i].addr); }else { system(clear); printf(查找结束,未查找到相关信息...\n); } return 0; } int phone_find() { char phone_num[20] {0}; system(clear); printf(请输入你要查找的电话号码:); scanf(%s, phone_num); int i 0; int find_flag 0; while(addr_people[i].serial_num ! -1) { if(!strcmp(addr_people[i].phone, phone_num)) { find_flag 1; break; } i; } if(find_flag 1) { system(clear); printf(查找结束...\n); printf(num:%-3d|name:%-10s|age:%-2d|sex:%-3s|phone:%-15s|addr:%-10s\n, addr_people[i].serial_num, addr_people[i].name, addr_people[i].age, addr_people[i].sex, addr_people[i].phone, addr_people[i].addr); }else { system(clear); printf(查找结束,未查找到相关信息...\n); } return 0; } int SearchContact() { int num, i; printf(查找联系人\n); printf(1-序号查找\n2-名字查找\n3-电话查找\n请选择你要查找的方式:); scanf(%d, num); switch(num) { case 1: num_find(); break; case 2: name_find(); break; case 3: phone_find(); break; default: printf(输入错误,返回上一级...\n); break; } return 0; } int modify_data(int i, int j, char *input_str) { switch(j) { case 1://name strcpy(addr_people[i].name, input_str); break; case 2://age addr_people[i].age atoi(input_str); break; case 3://sex strcpy(addr_people[i].sex, input_str); break; case 4://phone strcpy(addr_people[i].phone, input_str); break; case 5://addr strcpy(addr_people[i].addr, input_str); break; } return 0; } int ModifyContact() { int num, count; int i 0; printf(通讯录修改功能\n); int people_num_status ShowContact(); if(people_num_status -1) { printf(通讯录列表为空,无法进行修改操作...); return -1; } printf(请输入你要修改的序号:); scanf(%d, num); while(addr_people[i].serial_num ! -1) { if(addr_people[i].serial_num num) { int j; for(j 0; j 5; j) { char input_str[30] {0}; printf(tips:\n1-name\t2-age\n3-sex\t4-phone\n5-addr\n请输入你要修改的内容如果该项不修改请输入n\n[%d]--, j 1); scanf(%s, input_str); if(!strcmp(input_str, n)) continue; modify_data(i, j 1, input_str); } break; } i; } return 0; } int ShowContact() { printf(通讯录列表\n); int i 0; if(addr_people[0].serial_num -1) { printf(通讯录列表为空!\n); return -1; } while(addr_people[i].serial_num ! -1) { printf(num:%-3d|name:%-10s|age:%-2d|sex:%-3s|phone:%-15s|addr:%-10s\n, addr_people[i].serial_num, addr_people[i].name, addr_people[i].age, addr_people[i].sex, addr_people[i].phone, addr_people[i].addr); i; } return 0; } int ImportContact() { arr_num 0; /* 重新导入前清空计数避免重复累加 */ printf(ready to import contact data!\n); FILE *file_fd NULL; char line[256]; if((file_fd fopen(contact_data.txt, r)) NULL) { printf(have not data file!\n); return -1; } while(fgets(line, sizeof(line), file_fd) ! NULL) { char serial_num[5] {0}; char user_name[20] {0}; char user_age[5] {0}; char user_sex[5] {0}; char user_phone[15] {0}; char user_addr[20] {0}; sscanf(line, num %s name %s age %s sex %s phone %s addr %s, serial_num, user_name, user_age, user_sex, user_phone, user_addr); if (arr_num PEOPLE_NUM) { printf(超过最大人数停止导入\n); break; } addr_people[arr_num].serial_num arr_num 1; strcpy(addr_people[arr_num].name, user_name); addr_people[arr_num].age atoi(user_age); strcpy(addr_people[arr_num].sex, user_sex); strcpy(addr_people[arr_num].phone, user_phone); strcpy(addr_people[arr_num].addr, user_addr); arr_num; /*printf(num:%-3d name:%-10s age:%-2d sex:%-3s phone:%-15s addr:%-10s\n, addr_people[num].serial_num, addr_people[num].name, addr_people[num].age, addr_people[num].sex, addr_people[num].phone, addr_people[num].addr);*/ } printf(import contact data over, import people[%d]!\n, arr_num); fclose(file_fd); return 0; } int ExportContact() { printf(ready to export contact data, will create contact_data.txt file!\n); FILE *file_fd NULL; file_fd fopen(contact_data.txt, w); if(file_fd NULL) { printf(create data file error!\n); return -1; } int i 0; while(addr_people[i].serial_num ! -1) { fprintf(file_fd, num %d name %s age %d sex %s phone %s addr %s\n, addr_people[i].serial_num, addr_people[i].name, addr_people[i].age, addr_people[i].sex, addr_people[i].phone, addr_people[i].addr); /*printf(num %d name %s age %d sex %s phone %s addr %s\n, addr_people[i].serial_num, addr_people[i].name, addr_people[i].age, addr_people[i].sex, addr_people[i].phone, addr_people[i].addr);*/ i; } printf(export contact data over!\n); fclose(file_fd); return 0; } int get_user_input() { int num; printf(请输入选择:); if (scanf(%d, num) ! 1) { int ch; while ((ch getchar()) ! \n ch ! EOF) { } return -1; } if (num 9 || num 0)//这里跟上面的回调函数的结构体数组里面的个数相关 return -1; return num; } void show_menu_list() { int i 0; printf(\n~~欢迎使用用户管理系统~~\n); printf(\n); while (menu[i].Function ! NULL) { printf( %d-%s\n, i 1, menu[i].func_str); i; } printf(\n); } int main() { int num, i; InitContact(); while (1) { show_menu_list(); num get_user_input(); system(clear);//清屏 if(num ! -1) menu[num - 1].Function(); else printf(输入选项无效,请重新输入...\n); } return 0; }十一、小结菜单用函数指针表驱动便于扩展。输入用带宽度的scanf不要使用不可移植的fflush(stdin)。导入前重置arr_num删除后重排serial_num添加前检查容量。清屏命令依赖 Linux 的clearWindows 可改为cls或条件编译。
【C语言】34-通讯录管理系统
作者简介Nebula嵌入式 | 嵌入式软件工程师技术背景22届普通二本院校毕业生专注于嵌入式软件开发MCU/RTOS/Linux应用/Linux驱动开发 持续学习中内容创作小红书、抖音、B站同名账号分享嵌入式知识和日常工作欢迎关注商务合作/需要学习资料联系️nebula0419备注商务合作/学习资料修订记录版本修改时间修改内容1.02023.3.18初稿Linux 下通讯录练习项目2.02024.6.7修正导入/删除逻辑与输入边界3.02026.7.30去掉 fflush(stdin)为 scanf 增加宽度限制4.02026.8.1梳理通讯录模块划分与结构体数组模型补强表驱动菜单、删除重排、导入导出与输入边界要点一、前言本文实现一个简易通讯录管理系统基于 Linux清屏使用clear。项目把前面学过的结构体数组、函数指针表驱动和文件 IO串成一条可运行链路内存里维护联系人磁盘用contact_data.txt做导入导出。耗时约三小时难免有边界可继续打磨欢迎留言指出。二、总体设计与功能总览读图要点核心能力添加、删除、搜索、修改、显示全部以及导入/导出持久化。容量上限PEOPLE_NUM100可后续改为动态开辟退出通过菜单项调用exit。功能清单保存最多 100 人信息后续可优化成动态开辟。增加人的信息。删除指定联系人的信息。查询指定联系人的信息。修改指定联系人的信息。显示所有联系人的信息。导入导出通讯录。人的信息字段名字、年龄、性别、电话、地址。知识点结构体数组、函数指针回调、文件操作函数。三、数据模型结构体与数组读图要点PEOPLE_INFO描述单条记录addr_people[PEOPLE_NUM]是固定容量池。有效人数用arr_num维护空槽以serial_num -1标记初始化时全部置 -1。typedef struct { int serial_num; char name[20]; int age; char sex[5]; char phone[15]; char addr[20]; } PEOPLE_INFO; PEOPLE_INFO addr_people[PEOPLE_NUM]; int arr_num 0; /* 通讯录人数 */四、菜单表驱动函数指针读图要点MENU_LIST把「菜单文字」与「函数指针」绑定末尾{NULL, NULL}作哨兵。用户输入num后执行menu[num - 1].Function()避免冗长switch扩展时只加表项。typedef struct { char *func_str; int (*Function)(void); } MENU_LIST; MENU_LIST menu[] { {退出系统, Exitsys}, {添加, AddContact}, {删除, DelContact}, {搜索, SearchContact}, {修改, ModifyContact}, {显示所有联系人, ShowContact}, {导入, ImportContact}, {导出, ExportContact}, {NULL, NULL} };五、添加与容量检查读图要点添加前先判arr_num PEOPLE_NUM满员直接返回防止写越界。字段用带宽度的scanf如%19s、%14s写入后arr_numserial_num arr_num 1写入当下槽位时用当前下标 1。六、删除移位与序号重排读图要点按序号定位后后续元素整体前移覆盖空洞再arr_num--。删除后必须重排serial_num i 1并把尾槽置serial_num -1保证序号连续、遍历可停。七、三种搜索模式读图要点搜索入口再分子菜单序号 / 名字 / 电话分别线性扫描匹配。名字、电话用strcmp命中打印整行未命中给出明确提示。修改功能按序号定位后对 name/age/sex/phone/addr 五项依次询问输入n可跳过该项。八、导入导出与文件 IO读图要点导出fprintf按行写出到同级目录contact_data.txt导入fgetssscanf解析回数组。导入开头必须arr_num 0否则重复导入会累加甚至越界。文本行格式示例num 1 name Zhang age 25 sex M phone 13800000000 addr Beijing九、主循环与输入边界读图要点InitContact后进入while(1)显示菜单 → 读选项 → 清屏 → 回调对应函数。输入侧带宽度scanf、非法输入时吞掉残留字符不要用不可移植的fflush(stdin)clear依赖 LinuxWindows 可改为cls或条件编译。十、完整代码#include stdio.h #include stdlib.h #include string.h int Exitsys(); int InitContact(); int AddContact(); int DelContact(); int SearchContact(); int ModifyContact(); int ShowContact(); int SortContact(); int ImportContact(); int ExportContact(); #define MENU_LEN 10 #define PEOPLE_NUM 100 typedef struct { int serial_num; char name[20]; int age; char sex[5]; char phone[15]; char addr[20]; } PEOPLE_INFO; typedef struct { char *func_str; int (*Function)(void); } MENU_LIST; PEOPLE_INFO addr_people[PEOPLE_NUM]; int arr_num 0;//通讯录人数 MENU_LIST menu[] { {退出系统, Exitsys}, // 退出系统 {添加, AddContact}, // 添加 {删除, DelContact}, // 删除 {搜索, SearchContact}, // 搜索 {修改, ModifyContact}, // 修改 {显示所有联系人, ShowContact}, // 显示所有联系人 //{排序, SortContact}, // 排序 {导入, ImportContact}, // 导入 {导出, ExportContact}, // 导出 {NULL, NULL} }; int Exitsys() { exit(0); return 0; } int InitContact() { /* init arr */ int i; for(i 0;i PEOPLE_NUM; i) { addr_people[i].serial_num -1; } return 0; } /* 添加用户 */ int AddContact() { if (arr_num PEOPLE_NUM) { printf(通讯录已满(%d)无法继续添加!\n, PEOPLE_NUM); return -1; } char user_name[20] {0}; int user_age 0; char user_sex[5] {0}; char user_phone[15] {0}; char user_addr[20] {0}; printf(开始添加联系人!\n); printf(请输入联系人的姓名); scanf(%19s, user_name); printf(请输入联系人的年龄); scanf(%d, user_age); printf(请输入联系人的性别); scanf(%4s, user_sex); printf(请输入联系人的电话); scanf(%14s, user_phone); printf(请输入联系人的地址); scanf(%19s, user_addr); addr_people[arr_num].serial_num arr_num 1; strcpy(addr_people[arr_num].name, user_name); addr_people[arr_num].age user_age; strcpy(addr_people[arr_num].sex, user_sex); strcpy(addr_people[arr_num].phone, user_phone); strcpy(addr_people[arr_num].addr, user_addr); printf(用户 %s 添加成功\n, user_name); arr_num; return 0; } int DelContact() { int num; int people_num_status ShowContact(); if(people_num_status -1) { printf(通讯录列表为空,无法进行修改操作...); return -1; } printf(请输入你要删除的联系人的序号(1-%d):, arr_num); if (scanf(%d, num) ! 1 || num 1 || num arr_num) { printf(输入错误!\n); return -1; } num--; int i; for (i num; i arr_num - 1; i) { addr_people[i] addr_people[i 1]; } arr_num--; if (arr_num 0 arr_num PEOPLE_NUM) addr_people[arr_num].serial_num -1; for (i 0; i arr_num; i) addr_people[i].serial_num i 1; return 0; } int num_find() { int serial_num; system(clear); printf(请输入你要查找的序号:); scanf(%d, serial_num); int i 0; int find_flag 0; while(addr_people[i].serial_num ! -1) { if(addr_people[i].serial_num serial_num) { find_flag 1; break; } i; } if(find_flag 1) { system(clear); printf(查找结束...\n); printf(num:%-3d|name:%-10s|age:%-2d|sex:%-3s|phone:%-15s|addr:%-10s\n, addr_people[i].serial_num, addr_people[i].name, addr_people[i].age, addr_people[i].sex, addr_people[i].phone, addr_people[i].addr); }else { system(clear); printf(查找结束,未查找到相关信息...\n); } return 0; } int name_find() { char user_name[20] {0}; system(clear); printf(请输入你要查找的用户名:); scanf(%19s, user_name); int i 0; int find_flag 0; while(addr_people[i].serial_num ! -1) { if(!strcmp(addr_people[i].name, user_name)) { find_flag 1; break; } i; } if(find_flag 1) { system(clear); printf(查找结束...\n); printf(num:%-3d|name:%-10s|age:%-2d|sex:%-3s|phone:%-15s|addr:%-10s\n, addr_people[i].serial_num, addr_people[i].name, addr_people[i].age, addr_people[i].sex, addr_people[i].phone, addr_people[i].addr); }else { system(clear); printf(查找结束,未查找到相关信息...\n); } return 0; } int phone_find() { char phone_num[20] {0}; system(clear); printf(请输入你要查找的电话号码:); scanf(%s, phone_num); int i 0; int find_flag 0; while(addr_people[i].serial_num ! -1) { if(!strcmp(addr_people[i].phone, phone_num)) { find_flag 1; break; } i; } if(find_flag 1) { system(clear); printf(查找结束...\n); printf(num:%-3d|name:%-10s|age:%-2d|sex:%-3s|phone:%-15s|addr:%-10s\n, addr_people[i].serial_num, addr_people[i].name, addr_people[i].age, addr_people[i].sex, addr_people[i].phone, addr_people[i].addr); }else { system(clear); printf(查找结束,未查找到相关信息...\n); } return 0; } int SearchContact() { int num, i; printf(查找联系人\n); printf(1-序号查找\n2-名字查找\n3-电话查找\n请选择你要查找的方式:); scanf(%d, num); switch(num) { case 1: num_find(); break; case 2: name_find(); break; case 3: phone_find(); break; default: printf(输入错误,返回上一级...\n); break; } return 0; } int modify_data(int i, int j, char *input_str) { switch(j) { case 1://name strcpy(addr_people[i].name, input_str); break; case 2://age addr_people[i].age atoi(input_str); break; case 3://sex strcpy(addr_people[i].sex, input_str); break; case 4://phone strcpy(addr_people[i].phone, input_str); break; case 5://addr strcpy(addr_people[i].addr, input_str); break; } return 0; } int ModifyContact() { int num, count; int i 0; printf(通讯录修改功能\n); int people_num_status ShowContact(); if(people_num_status -1) { printf(通讯录列表为空,无法进行修改操作...); return -1; } printf(请输入你要修改的序号:); scanf(%d, num); while(addr_people[i].serial_num ! -1) { if(addr_people[i].serial_num num) { int j; for(j 0; j 5; j) { char input_str[30] {0}; printf(tips:\n1-name\t2-age\n3-sex\t4-phone\n5-addr\n请输入你要修改的内容如果该项不修改请输入n\n[%d]--, j 1); scanf(%s, input_str); if(!strcmp(input_str, n)) continue; modify_data(i, j 1, input_str); } break; } i; } return 0; } int ShowContact() { printf(通讯录列表\n); int i 0; if(addr_people[0].serial_num -1) { printf(通讯录列表为空!\n); return -1; } while(addr_people[i].serial_num ! -1) { printf(num:%-3d|name:%-10s|age:%-2d|sex:%-3s|phone:%-15s|addr:%-10s\n, addr_people[i].serial_num, addr_people[i].name, addr_people[i].age, addr_people[i].sex, addr_people[i].phone, addr_people[i].addr); i; } return 0; } int ImportContact() { arr_num 0; /* 重新导入前清空计数避免重复累加 */ printf(ready to import contact data!\n); FILE *file_fd NULL; char line[256]; if((file_fd fopen(contact_data.txt, r)) NULL) { printf(have not data file!\n); return -1; } while(fgets(line, sizeof(line), file_fd) ! NULL) { char serial_num[5] {0}; char user_name[20] {0}; char user_age[5] {0}; char user_sex[5] {0}; char user_phone[15] {0}; char user_addr[20] {0}; sscanf(line, num %s name %s age %s sex %s phone %s addr %s, serial_num, user_name, user_age, user_sex, user_phone, user_addr); if (arr_num PEOPLE_NUM) { printf(超过最大人数停止导入\n); break; } addr_people[arr_num].serial_num arr_num 1; strcpy(addr_people[arr_num].name, user_name); addr_people[arr_num].age atoi(user_age); strcpy(addr_people[arr_num].sex, user_sex); strcpy(addr_people[arr_num].phone, user_phone); strcpy(addr_people[arr_num].addr, user_addr); arr_num; /*printf(num:%-3d name:%-10s age:%-2d sex:%-3s phone:%-15s addr:%-10s\n, addr_people[num].serial_num, addr_people[num].name, addr_people[num].age, addr_people[num].sex, addr_people[num].phone, addr_people[num].addr);*/ } printf(import contact data over, import people[%d]!\n, arr_num); fclose(file_fd); return 0; } int ExportContact() { printf(ready to export contact data, will create contact_data.txt file!\n); FILE *file_fd NULL; file_fd fopen(contact_data.txt, w); if(file_fd NULL) { printf(create data file error!\n); return -1; } int i 0; while(addr_people[i].serial_num ! -1) { fprintf(file_fd, num %d name %s age %d sex %s phone %s addr %s\n, addr_people[i].serial_num, addr_people[i].name, addr_people[i].age, addr_people[i].sex, addr_people[i].phone, addr_people[i].addr); /*printf(num %d name %s age %d sex %s phone %s addr %s\n, addr_people[i].serial_num, addr_people[i].name, addr_people[i].age, addr_people[i].sex, addr_people[i].phone, addr_people[i].addr);*/ i; } printf(export contact data over!\n); fclose(file_fd); return 0; } int get_user_input() { int num; printf(请输入选择:); if (scanf(%d, num) ! 1) { int ch; while ((ch getchar()) ! \n ch ! EOF) { } return -1; } if (num 9 || num 0)//这里跟上面的回调函数的结构体数组里面的个数相关 return -1; return num; } void show_menu_list() { int i 0; printf(\n~~欢迎使用用户管理系统~~\n); printf(\n); while (menu[i].Function ! NULL) { printf( %d-%s\n, i 1, menu[i].func_str); i; } printf(\n); } int main() { int num, i; InitContact(); while (1) { show_menu_list(); num get_user_input(); system(clear);//清屏 if(num ! -1) menu[num - 1].Function(); else printf(输入选项无效,请重新输入...\n); } return 0; }十一、小结菜单用函数指针表驱动便于扩展。输入用带宽度的scanf不要使用不可移植的fflush(stdin)。导入前重置arr_num删除后重排serial_num添加前检查容量。清屏命令依赖 Linux 的clearWindows 可改为cls或条件编译。