C语言学习笔记20260714-分文件通讯录完整实现(程序退出不丢失通讯录) C语言学习笔记20260714-分文件通讯录完整实现程序退出不丢失通讯录 学习目标本次学习的核心目标是实现通讯录数据的持久化存储。在传统的内存操作程序中数据仅存在于运行时的内存空间一旦程序退出所有数据随之丢失。通过引入文件操作我们需要达成以下效果数据保留程序退出后通讯录数据完整保存在本地文件中。自动加载下次启动程序时自动从文件读取历史数据无需手动重新录入。实时同步任何增、删、改操作完成后立即同步更新文件确保数据一致性。 核心思路实现持久化并非复杂的算法问题而是对数据流向的控制。整体设计遵循“启动加载变动保存”的原则二进制读写使用fread和fwrite进行二进制操作。相比文本格式化读写二进制方式无需处理字符串解析、空格换行等格式问题直接按内存结构读写效率高且不易出错。启动加载 (LoadContact)在main函数初始化通讯录后立即尝试打开数据文件。若文件存在读取人数和人员数组若文件不存在首次运行则保持空通讯录状态不报错。变动保存 (SaveContact)在AddContact、DelContact、ModifyContact、SortContact等修改内存数据的函数末尾统一调用保存函数。将当前人数和人员数组覆盖写入文件。 关键代码解析1. 数据加载LoadContact该函数负责在程序启动时“恢复现场”。voidLoadContact(Contact*pc){FILE*pffopen(contact.dat,rb);// 以二进制读方式打开if(pfNULL){// 文件不存在不是错误可能是第一次运行初始化为空即可return;}// 1. 读取当前联系人数量fread((pc-count),sizeof(int),1,pf);// 2. 根据数量读取具体的人员数据块fread(pc-data,sizeof(PeoInfo),pc-count,pf);fclose(pf);printf( 已加载 %d 条历史联系人记录。\n,pc-count);}容错处理fopen返回NULL时直接return避免首次运行因无文件而崩溃。分步读取先读count再读data。这保证了读取的数据量与实际存储量一致避免读取垃圾数据。2. 数据保存SaveContact该函数负责将内存快照“固化”到磁盘。voidSaveContact(constContact*pc){FILE*pffopen(contact.dat,wb);// 以二进制写方式打开if(pfNULL){printf( 错误无法保存文件\n);return;}// 1. 写入当前联系人数量fwrite((pc-count),sizeof(int),1,pf);// 2. 写入所有人员数据块fwrite(pc-data,sizeof(PeoInfo),pc-count,pf);fclose(pf);}覆盖写入使用wb模式每次保存都会清空旧文件并写入最新全量数据。对于百条级别的数据这种方式简单可靠无需处理文件中间插入/删除的复杂逻辑。结构体整块写入fwrite(pc-data, sizeof(PeoInfo), pc-count, pf)直接将结构体数组的内存镜像写入文件这是二进制存储的精髓。 完整代码展示1. 头文件contact.h定义数据结构与函数接口新增文件操作声明。#pragmaonce#ifndef__CONTACT_H__#define__CONTACT_H__#includestdio.h#includestring.h#includestdlib.h#defineMAX_PEOPLE100#defineNAME_LEN20#defineSEX_LEN6#defineTEL_LEN15#defineADDR_LEN30// 单人信息结构体typedefstructPeoInfo{charname[NAME_LEN];intage;charsex[SEX_LEN];chartel[TEL_LEN];charaddr[ADDR_LEN];}PeoInfo;// 通讯录结构体typedefstructContact{PeoInfo data[MAX_PEOPLE];intcount;// 当前有效联系人个数}Contact;// 初始化通讯录voidInitContact(Contact*pc);// 加载通讯录从文件voidLoadContact(Contact*pc);// 保存通讯录到文件voidSaveContact(constContact*pc);// 1. 新增联系人voidAddContact(Contact*pc);// 2. 显示所有联系人voidShowContact(constContact*pc);// 3. 查找联系人按姓名返回下标无则-1intFindByName(constContact*pc,charname[]);// 4. 删除指定联系人voidDelContact(Contact*pc);// 5. 修改联系人信息voidModifyContact(Contact*pc);// 6. 搜索联系人并打印voidSearchContact(constContact*pc);// 7. 按姓名排序联系人voidSortContact(Contact*pc);#endif2. 功能实现contact.c包含文件读写逻辑及业务功能在修改操作后自动调用保存。#define_CRT_SECURE_NO_WARNINGS#includecontact.h// 初始化通讯录voidInitContact(Contact*pc){pc-count0;memset(pc-data,0,sizeof(pc-data));}// 从文件加载数据voidLoadContact(Contact*pc){FILE*pffopen(contact.dat,rb);if(pfNULL){return;}fread((pc-count),sizeof(int),1,pf);fread(pc-data,sizeof(PeoInfo),pc-count,pf);fclose(pf);printf( 已加载 %d 条历史联系人记录。\n,pc-count);}// 保存数据到文件voidSaveContact(constContact*pc){FILE*pffopen(contact.dat,wb);if(pfNULL){printf( 错误无法保存文件\n);return;}fwrite((pc-count),sizeof(int),1,pf);fwrite(pc-data,sizeof(PeoInfo),pc-count,pf);fclose(pf);}// 新增联系人voidAddContact(Contact*pc){if(pc-countMAX_PEOPLE){printf(通讯录已满无法添加\n);return;}printf(请输入姓名);scanf(%s,pc-data[pc-count].name);printf(请输入年龄);scanf(%d,pc-data[pc-count].age);printf(请输入性别);scanf(%s,pc-data[pc-count].sex);printf(请输入电话);scanf(%s,pc-data[pc-count].tel);printf(请输入地址);scanf(%s,pc-data[pc-count].addr);pc-count;SaveContact(pc);// 数据变动立即保存printf(添加成功\n);}// 显示全部联系人voidShowContact(constContact*pc){if(pc-count0){printf(通讯录为空\n);return;}printf(%-10s %-5s %-6s %-15s %-20s\n,姓名,年龄,性别,电话,地址);for(inti0;ipc-count;i){printf(%-10s %-5d %-6s %-15s %-20s\n,pc-data[i].name,pc-data[i].age,pc-data[i].sex,pc-data[i].tel,pc-data[i].addr);}}// 根据姓名查找返回下标找不到返回-1intFindByName(constContact*pc,charname[]){for(inti0;ipc-count;i){if(strcmp(pc-data[i].name,name)0){returni;}}return-1;}// 删除联系人voidDelContact(Contact*pc){if(pc-count0){printf(通讯录为空无需删除\n);return;}charname[NAME_LEN];printf(请输入要删除的姓名);scanf(%s,name);intposFindByName(pc,name);if(pos-1){printf(未找到该联系人\n);return;}// 后续数据前移覆盖for(intipos;ipc-count-1;i){pc-data[i]pc-data[i1];}pc-count--;SaveContact(pc);// 数据变动立即保存printf(删除成功\n);}// 修改联系人voidModifyContact(Contact*pc){if(pc-count0){printf(通讯录为空\n);return;}charname[NAME_LEN];printf(请输入要修改的姓名);scanf(%s,name);intposFindByName(pc,name);if(pos-1){printf(未找到该联系人\n);return;}printf(请输入新姓名);scanf(%s,pc-data[pos].name);printf(请输入新年龄);scanf(%d,pc-data[pos].age);printf(请输入新性别);scanf(%s,pc-data[pos].sex);printf(请输入新电话);scanf(%s,pc-data[pos].tel);printf(请输入新地址);scanf(%s,pc-data[pos].addr);SaveContact(pc);// 数据变动立即保存printf(修改完成\n);}// 查找并打印联系人voidSearchContact(constContact*pc){if(pc-count0){printf(通讯录为空\n);return;}charname[NAME_LEN];printf(请输入要查找的姓名);scanf(%s,name);intposFindByName(pc,name);if(pos-1){printf(未找到该联系人\n);return;}printf(查询结果\n);printf(%-10s %-5s %-6s %-15s %-20s\n,姓名,年龄,性别,电话,地址);printf(%-10s %-5d %-6s %-15s %-20s\n,pc-data[pos].name,pc-data[pos].age,pc-data[pos].sex,pc-data[pos].tel,pc-data[pos].addr);}// 按姓名升序排序冒泡排序voidSortContact(Contact*pc){if(pc-count1){printf(联系人数量不足无需排序\n);return;}for(inti0;ipc-count-1;i){for(intj0;jpc-count-1-i;j){if(strcmp(pc-data[j].name,pc-data[j1].name)0){PeoInfo temppc-data[j];pc-data[j]pc-data[j1];pc-data[j1]temp;}}}SaveContact(pc);// 数据变动立即保存printf(排序完成\n);}3. 主程序stu20260629.c程序入口负责加载数据与菜单交互。#define_CRT_SECURE_NO_WARNINGS#includecontact.hvoidMenu(){printf(通讯录\n);printf(1. 新增联系人 2. 删除联系人\n);printf(3. 查找联系人 4. 修改联系人\n);printf(5. 联系人排序 6. 显示全部\n);printf(0. 退出程序\n);printf(\n);printf(请输入功能序号);}intmain(){Contact con;InitContact(con);// 程序启动时加载文件数据LoadContact(con);intinput0;do{Menu();scanf(%d,input);switch(input){case1:AddContact(con);break;case2:DelContact(con);break;case3:SearchContact(con);break;case4:ModifyContact(con);break;case5:SortContact(con);break;case6:ShowContact(con);break;case0:printf(程序退出再见\n);break;default:printf(输入错误请重新选择\n);break;}printf(\n);}while(input!0);return0;}