通讯录实现之进阶版将通讯录数据保存在文件中(完整代码)

我们在之前的博客中已经写过两版通讯录了:

第一版是用C语言实现了通讯录,但是通讯录的存储人数信息是固定的,用完就没有了

感兴趣的可以转到对应博客看一下,附带链接:第一版通讯录

第二版是在第一版的基础上动态开辟内存,使这个通讯录可以无限(只有内存足够大)存储人的信息

感兴趣的可以转到对应博客看一下,附带链接:第二版通讯录

今天我们要实现的是第三版,建立在第二版的基础上,将写入通讯录的人的信息保存在文件中

这里附带我们讲解文件操作的链接,不了解的小伙伴可以先去看一下文件操作:C语言之文件操作

我们前两版的通讯录只要结束了程序我们之前存入内存的数据就都被销毁了,是没办法保存下来的,下次运行程序我们还得重新存入这部分人的信息,这样是很不方便的。但是我们现在已经学习了文件操作这部分知识,我们现在可以做到把已经写入通讯录中人的信息保存到文件中,也就是硬盘中,当我们结束通讯录程序的代码执行,这些人的信息依旧是存在的,我们只要打开对应文件就可以看到,下次想要在存入人的信息,可以直接存入别人的信息,不用在存入已经存入的人的信息!

我们在这篇里是不会详细介绍它这样写的原理的,因为这部分讲解在实现第一版通讯录就已经说的很清楚了。

好,现在交代清楚了,我们话不多说,上代码!!!


目录

test .c

Contact.c

Contact.h

运行结果展示


test .c

//实现将通讯录数据写入文件中(硬盘中)实现数据的永久保存
//里面存放人的信息,包括姓名,年龄,性别
//实现的通讯录功能有:
//电话号码和家庭住址
//结合枚举,必要时要增容
//它包括以下功能
//1.增加联系人
//2.删除指定联系人
//3.查找指定联系人
//4.修改指定联系人
//5.显示所有联系人
//6.对所有联系人进行排序(按姓名)
//7.退出通讯录(这时要记得释放动态内存开辟的空间,避免内存泄漏#include"contact.h"
//加入枚举,给下面Switch case语句一个提示,函数写到了通讯录的哪个功能
enum contact
{exitContact,addContact,delContact,showContact,sehContact,mofContact,sortContact,
};
void menu(void)
{printf("*******************************************\n");printf("**********     1.AddContact      **********\n");printf("**********     2.DelContact      **********\n");printf("**********     3.ShowContact     **********\n");printf("**********     4.SehContact      **********\n");printf("**********     5.MofContact      **********\n");printf("**********     6.SortContact     **********\n");printf("**********     0.ExitContact     **********\n");printf("*******************************************\n");
}
int main()
{int input = 0;Contact con;//初始化通讯录InitContact(&con);do{menu();printf("请选择:>");scanf("%d", &input);switch (input){case addContact:AddContact(&con);break;case delContact:DelContact(&con);break;case showContact:ShowContact(&con);break;case sehContact:SehContact(&con);break;case mofContact:MofContact(&con);break;case sortContact:SortContact(&con);break;case exitContact://把通讯录数据存入文件中SaveContact(&con);//销毁通讯录,进行动态空间的释放DestoryContact(&con);break;default:printf("输入错误,请重新输入!\n");break;}} while (input);return 0;
}

Contact.c

#include"contact.h"//空间增容函数
void check_capacity(Contact* pc)
{assert(pc);if (pc->sz == pc->capacity){//通讯录已满,进行增容PeopInfo* str = (PeopInfo*)realloc(pc->data, (pc->capacity + INC_SZ) * sizeof(PeopInfo));if (str == NULL){perror("realloc");return;}pc->data = str;pc->capacity += INC_SZ;//总容量增加printf("空间增容成功,可以继续添加联系人\n");}
}//通过名字查找
int FindByName(const Contact* pc, char* Name)
{assert(pc);int i = 0;if (pc->sz == 0){printf("通讯录为空,无法查找!");return;}for (i = 0; i < pc->sz; i++){if (strcmp(Name, pc->data[i].Name) == 0)return i;}return -1;
}//初始化这个通讯录,初始化为对应的值,每次打开通讯录上次存入文件的信息
//都不会被覆盖,增加一个函数功能,加载文件信息到通讯录
void InitContact(Contact* pc)
{assert(pc);//为通讯录存放人的信息的结构体分配初始空间,并把里面数据直接//初始化为0,calloc函数很合适PeopInfo* str = (PeopInfo*)calloc(DEFAULT_SZ, sizeof(PeopInfo));if (str == NULL){perror("calloc");return;}pc->data = str;pc->sz = 0;pc->capacity = DEFAULT_SZ;//加载文件中的信息到通讯录LoadContact(pc);
}//加载文件中的信息到通讯录
void LoadContact(Contact* pc)
{assert(pc);//从文件中读取通讯录数据FILE* pf = fopen("Contact.txt", "rb");if (pf == NULL){perror("LoadContact");return;}//读数据PeopInfo tmp = { 0 };//存放读到的数据int i = 0;while (fread(&tmp,sizeof(PeopInfo),1,pf)){//增容问题check_capacity(pc);pc->data[i] = tmp;pc->sz++;i++;}//读取完毕,关闭文件fclose(pf);pf = NULL;
}//把通讯录数据存入文件中
void SaveContact(Contact* pc)
{assert(pc);//写数据//以二进制打开文件写入FILE* pf = fopen("Contact.txt", "wb");if (pf == NULL){perror("SaveContact");return;}//开始写入int i = 0;for (i = 0; i < pc->sz; i++){//这里大家可以自己尝试一下,fprintf和fputs 是否可以写入数据fwrite(pc->data + i, sizeof(PeopInfo), 1, pf);}//关闭文件fclose(pf);pf = NULL;printf("保存数据成功\n");
}//增加通讯录联系人
void AddContact(Contact* pc)
{assert(pc);check_capacity(pc);//检查通讯录是否需要增容//增加人的信息printf("请输入联系人姓名:>");scanf("%s", pc->data[pc->sz].Name);printf("请输入联系人年龄:>");scanf("%d", &pc->data[pc->sz].Age);printf("请输入联系人性别:>");scanf("%s", pc->data[pc->sz].Sex);printf("请输入联系人电话号码:>");scanf("%s", pc->data[pc->sz].Tele);printf("请输入联系人家庭住址:>");scanf("%s", pc->data[pc->sz].Addr);pc->sz++;
}
//删除指定联系人
void DelContact(Contact* pc)
{assert(pc);char Name[NAME_MAX] = { 0 };int i = 0;if (pc->sz == 0){printf("通讯录为空,无法删除!\n");return;}printf("请输入要删除的人的姓名:>");scanf("%s", Name);int pos = FindByName(pc, Name);if (pos == -1){printf("要删除的联系人不存在!\n");return;}for (i = pos; i < pc->sz - 1; i++){pc->data[i] = pc->data[i + 1];}pc->sz--;printf("删除联系人成功!\n");
}//显示所有联系人
void ShowContact(const Contact* pc)
{assert(pc);if (pc->sz == 0){printf("通讯录为空,无法显示!\n");return;}int i = 0;printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话号码", "家庭住址");for (i = 0; i < pc->sz; i++){printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n",pc->data[i].Name,pc->data[i].Age,pc->data[i].Sex,pc->data[i].Tele,pc->data[i].Addr);}
}//查找指定联系人
void SehContact(const Contact* pc)
{assert(pc);if (pc->sz == 0){printf("通讯录为空,无法查找!\n");return;}char Name[NAME_MAX] = { 0 };printf("请输入要查找的人的姓名:>");scanf("%s", Name);int pos = FindByName(pc, Name);if (pos == -1){printf("要查找的联系人不存在!\n");return;}printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话号码", "家庭住址");printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n",pc->data[pos].Name,pc->data[pos].Age,pc->data[pos].Sex,pc->data[pos].Tele,pc->data[pos].Addr);
}
//修改指点联系人的信息
void MofContact(Contact* pc)
{assert(pc);if (pc->sz == 0){printf("通讯录为空,无法修改!\n");return;}char Name[NAME_MAX] = { 0 };printf("请输入要修改的人的姓名:>");scanf("%s", Name);int pos = FindByName(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].Tele);printf("请输入联系人家庭住址:>");scanf("%s", pc->data[pos].Addr);
}//对所有联系人按姓名进行排序
void SortContact(const Contact* pc)
{assert(pc);int i = 0;int j = 0;for (i = 0; i < pc->sz; i++){for (j = i; j < pc->sz; j++){if (strcmp(pc->data[i].Name, pc->data[j].Name) > 0){PeopInfo temp[] = { 0 };temp[0] = pc->data[i];pc->data[i] = pc->data[j];pc->data[j] = temp[0];}}}ShowContact(pc);//显示一下排列结果
}//销毁通讯录,释放动态内存空间
void DestoryContact(Contact* pc)
{free(pc->data);pc->data = NULL;pc->sz = 0;pc->capacity = 0;pc = NULL;printf("通讯录已退出\n");
}

Contact.h

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<assert.h>#define DEFAULT_SZ 3 //初始通讯录内存放的联系人个数
#define INC_SZ 2     //每次增容的空间
#define NAME_MAX 30
#define SEX_MAX 5
#define TELE_MAX 12
#define ADDR_MAX 30//创建结构体存放有关人的信息
typedef struct PeopInfo
{char Name[NAME_MAX];int Age;char Sex[SEX_MAX];char Tele[TELE_MAX];char Addr[ADDR_MAX];
}PeopInfo;//创建初始通讯录,里面存放人的信息,初始内存大小
typedef struct Contact
{PeopInfo* data;  //存放人的信息int sz;int capacity;   //初始内存
}Contact;//空间增容函数
void check_capacity(Contact* pc);//初始化这个通讯录,初始化为对应的值
void InitContact(Contact* pc);
//增加通讯录联系人
void AddContact(Contact* pc);
//删除指定联系人
void DelContact(Contact* pc);
//显示所有联系人
void ShowContact(const Contact* pc);
//通过名字查找
int FindByName(const Contact* pc, char* Name);
//查找指定联系人
void SehContact(const Contact* pc);
//修改指点联系人的信息
void MofContact(Contact* pc);
//对所有联系人按姓名进行排序
void SortContact(const Contact* pc);//把通讯录数据存入文件中
void SaveContact(Contact* pc);//加载文件中的信息到通讯录
void LoadContact(Contact* pc);//销毁通讯录,释放动态内存空间
void DestoryContact(Contact* pc);

运行结果展示

程序代码上的显示(已经存入数据)

在文件中的显示


总体的代码实现就是这样了,希望大家可以理解哟!

我们下期再见!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/145279.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

三大开源向量数据库大比拼

向量数据库具有一系列广泛的好处&#xff0c;特别是在生成式人工智能方面&#xff0c;更具体地说&#xff0c;是在大语言模型&#xff08;LLM&#xff09;方面。这些好处包括先进的索引和精确的相似度搜索&#xff0c;有助于交付强大的先进项目。 本文将对三种开源向量数据库&…

“开源 vs. 闭源:大模型的未来发展趋势预测“——探讨大模型未来的发展方向

文章目录 每日一句正能量前言什么是大模型的开源与闭源开源与闭源的定义和特点开源的意义开源和闭源的优劣势比较不同的大模型企业&#xff0c;开源、闭源的策略不尽相同。企业在开发垂类模型时选择开源还是闭源大模型开源vs 闭源&#xff1a;两者并非选择题后记 每日一句正能量…

【网络】TCP协议的相关实验

TCP协议的相关实验 一、理解listen的第二个参数1、实验现象2、TCP 半连接队列和全连接队列3、关于listen的第二个参数的一些问题4、SYN洪水Ⅰ、什么是SYN洪水攻击Ⅱ、如何解决SYN洪水攻击&#xff1f; 二、使用Wireshark分析TCP通信流程 一、理解listen的第二个参数 在编写TCP…

有什么进销存软件,比较适合零售行业日常开单要求及库存记录?

本文将为大家总结一下对于进销存软件要求&#xff1a; 基础功能&#xff1a;可以日常开单、退换货处理、出入库进阶功能&#xff1a;电脑、手机数据同步&#xff0c;保障数据安全&#xff0c;可进行数据分析 其实无论是小型创业公司&#xff0c;还是一家大型企业&#xff0c;…

MathType2024最新word公式编辑器

使用word进行论文编写时&#xff0c;常需要使用公式编辑器&#xff0c;但有些word中并没有公式编辑器&#xff0c;这时应该怎么办呢&#xff1f;本文将围绕word里没有公式编辑器怎么办&#xff0c;word中的公式编辑器怎么用的内容进行介绍。 一、word里没有公式编辑器怎么办 …

现货黄金职业交易员怎么使用技术分析?

职业的交易员每天要处理很多不同的信息&#xff0c;其中只一部分是涉及技术指标。在这一部分处理技术分析的时间里&#xff0c;只能再分出少之又少的时间给技术指标。那职业交易员会利用做技术指标做什么呢&#xff1f;下面我们就来讨论一下。 识别行情。技术指标的主要作用就是…

Digicert证书:您的网络安全守护神

在当今数字化的世界中&#xff0c;网络安全已经成为每一个企业和个人必须面对的问题。而Digicert品牌证书&#xff0c;就是您网络安全的最佳选择。它不仅具有强大的安全性和稳定性&#xff0c;还能广泛应用于各种场景&#xff0c;为您提供全方位的保护。 首先&#xff0c;我们要…

【Linux】Ubuntu16.04配置repo

Ubuntu16.04配置repo失败 在学习韦东山Linux嵌入式开发过程中&#xff0c;使用repo获取内核及工具链: git clone https://e.coding.net/codebug8/repo.gitmkdir -p 100ask_imx6ull-sdk && cd 100ask_imx6ull-sdk../repo/repo init -u https://gitee.com/weidongshan/m…

万能在线答题考试小程序源码系统 既能刷题 又能考试 带完整的搭建教程

现如今&#xff0c;线上学习和考试已经成为一种趋势。近年来&#xff0c;移动端的普及以及微信小程序的兴起&#xff0c;使得在线答题考试系统变得更加便捷和高效。今天罗峰就来给大家介绍一款万能在线答题考试小程序源码系统&#xff0c;既能刷题&#xff0c;又能考试&#xf…

Tosca 2023x 新功能介绍

Tosca/Structure的功能增强 热优化功能增强 在优化过程中&#xff0c;支持将对流边界条件转移至新创建的表面&#xff0c;方便更加真实地模拟传热行为。支持恒定传导。多物理场优化能力增强。通过使用多个输入面板对热和结构荷载进行分别输入&#xff0c;以支持同时对热和结构…

​软考-高级-系统架构设计师教程(清华第2版)【第10章 软件架构的演化和维护(P345~382)-思维导图】​

软考-高级-系统架构设计师教程&#xff08;清华第2版&#xff09;【第10章 软件架构的演化和维护&#xff08;P345~382&#xff09;-思维导图】 课本里章节里所有蓝色字体的思维导图

【k8s集群搭建(二):基于虚拟机的linux的k8s集群搭建_超详细_可视化界面Dashboard安装_记录全过程踩坑记录及解决方法】

在 master 执行 # 根据 在线配置文件 创建资源 kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.3.1/aio/deploy/recommended.yaml设置访问端口 # 修改配置文件 找到 type&#xff0c;将 ClusterIP 改成 NodePort kubectl edit svc kubernetes-…

2023年中国冲击波治疗仪市场发展趋势分析:未来市场增长空间更大[图]

冲击波在临床医学领域最早应用于体外冲击波碎石&#xff0c;在二十世纪八十年代末期&#xff0c;体外冲击波碎石技术开始被运用到骨科及康复理疗领域&#xff0c;经过十余年的临床研究&#xff0c;冲击波疗法日益完善&#xff0c;应用范围也日益扩大。冲击波作为一种介于保守疗…

【入门篇】1.7 Redis 之 codis 入门介绍

文章目录 1. 简介2. Codis的安装与配置下载编译源码安装1. 安装 Go 运行环境2. 设置编译环境3. 下载 Codis 源代码4. 编译 Codis 源代码 Docker 部署 3. Codis的架构Codis的架构图和组件Codis的工作流程 4. Codis的核心特性自动数据分片数据迁移高可用性全面支持Redis命令分布式…

【fbtft】如何添加fbtft驱动

获取lcd ic的datasheet&#xff0c;或者直接找到其他平台&#xff08;linux&#xff0c;stm32&#xff0c;esp32&#xff09;的驱动 我用的是合宙的esp32驱动&#xff0c;注意是c语言的&#xff0c;合宙上层用lua封装了&#xff0c;需要找到sdk源码。 源码路径&#xff1a; …

File类和IO流

我是南城余&#xff01;阿里云开发者平台专家博士证书获得者&#xff01; 欢迎关注我的博客&#xff01;一同成长&#xff01; 一名从事运维开发的worker&#xff0c;记录分享学习。 专注于AI&#xff0c;运维开发&#xff0c;windows Linux 系统领域的分享&#xff01; 本…

设置chunk自动扩展到多大

1. 设置chunk自动扩展 execute function task(modify chunk extendable on,8); 2. 设置dbs扩展到多大合适 execute function task(modify space sp sizes,testdb1024,1024,10240) testdb 初始1MB 下次扩1MB 最大10MB

appium+python自动化测试

获取APP的包名 1、aapt即Android Asset Packaging Tool&#xff0c;在SDK的build-tools目录下。该工具可以查看apk包名和launcherActivity 2、在android-sdk里面双击SDK-manager,下载buidl-tools 3、勾选build-tools&#xff0c;随便选一个版本&#xff0c;我这里选的是24的版…

宏集干货 | 手把手教你通过CODESYS V3进行PLC编程(三)

来源&#xff1a;宏集科技 工业物联网 宏集干货 | 手把手教你通过CODESYS V3进行PLC编程&#xff08;三&#xff09; 教程背景 通过之前的教程&#xff0c;我们已经为大家演示了宏集MC-Prime控制器的连接、试运行和CODESYS的安装&#xff0c;并创建了一个计数器项目。在本期教…

数据分析 - 分散性与变异的量度

全距 - 极差 处理变异性 方差度量 数值与均值的距离&#xff0c;也就是数据的差异性 标准差描述&#xff1a;典型值 和 均值的距离的方法&#xff0c;数据与均值的分散情况