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

news2024/11/23 18:30:15

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

第一版是用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.coloradmin.cn/o/1218010.html

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

相关文章

vscode Prettier配置

常用配置项&#xff1a; .prettierrc.json 是 Prettier 格式化工具的配置文件 {"printWidth": 200, // 指定行的最大长度"tabWidth": 2, // 指定缩进的空格数"useTabs": false, // 是否使用制表符进行缩进&#xff0c;默认为 false"singl…

GPTS全网刷屏!定制增长速度指数增长

还记的上周OpenAI刚刚举行完开发者大会&#xff0c;在大会上主要公布了三个事情&#xff1a; 新版本的GPT-4 Turbo&#xff1a;更强大、更便宜且支持128K新的助手API&#xff1a;让开发者更轻松地基于GPT构建辅助AI应用平台中新的多模态功能&#xff1a;包括视觉、图像创作&am…

SpringMVC调用流程

SpringMVC的调用流程 SpringMVC涉及组件理解&#xff1a; DispatcherServlet : SpringMVC提供&#xff0c;我们需要使用web.xml配置使其生效&#xff0c;它是整个流程处理的核心&#xff0c;所有请求都经过它的处理和分发&#xff01;[ CEO ] HandlerMapping : SpringMVC提供&…

如何理解Java是按值传递

在 Java 中&#xff0c;参数传递有两种方式&#xff1a;按值传递&#xff08;pass by value&#xff09;和按引用传递&#xff08;pass by reference&#xff09;。然而&#xff0c;Java 中的参数传递方式实际上是按值传递的。 按值传递的含义是&#xff1a; 在方法调用时&am…

华为 Mate 60 Pro 拆解:陆制零件比率上升至47% | 百能云芯

近日&#xff0c;日经新闻联合研究公司Fomalhaut Techno Solutions对华为 Mate 60 Pro 进行了拆解&#xff0c;揭示了这款于8月发布的新型智能手机的成本结构。拆解结果显示&#xff0c;该手机的国产零部件比例达到了47%&#xff0c;相较于三年前的 Mate 40 Pro&#xff0c;提高…

2.FastRunner定时任务Celery+RabbitMQ

注意&#xff1a;celery版本和Python冲突问题 不能用高版本Python 用3.5以下&#xff0c;因为项目的celery用的django-celery 3.2.2 python3.7 async关键字 冲突版本 celery3.x方案一&#xff1a; celery3.xpython3.6方案二 &#xff1a; celery4.xpython3.7 解决celery执…

Accelerate 0.24.0文档 三:超大模型推理(内存估算、Sharded checkpoints、bitsandbytes量化、分布式推理)

文章目录 一、内存估算1.1 Gradio Demos1.2 The Command 二、使用Accelerate加载超大模型2.1 模型加载的常规流程2.2 加载空模型2.3 分片检查点&#xff08;Sharded checkpoints&#xff09;2.4 示例&#xff1a;使用Accelerate推理GPT2-1.5B2.5 device_map 三、bitsandbytes量…

计算机毕业设计选题推荐-幼儿园管理微信小程序/安卓APP-项目实战

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…

微机原理_10

一、单项选择题(本大题共15小题,每小题3分,共45分。在每小题给出的四个备选项中,选出一个正确的答案。&#xff09; 1,将二进制数110110.01转换为十六进制为(&#xff09; A. 66.1H B. 36.4H C. 66.4 D. 36.2 2,一台计算机的字长是4个字节,含义是(&#xff09; A.能处理的最大…

soh估计:Data-driven prediction of battery cycle life before capacity degradation

文献思想 作者发现不同循环寿命的电池&#xff0c;第100次和第10次循环放电容量的差有不同&#xff0c;作者由这一现象&#xff0c;提取出了放电容量差的方差、平均值、最小值等特征&#xff0c;其中放电容量差的方差对数和循环寿命的对数的皮尔逊相关性高达-0.93&#xff0c;…

【精选】JavaScript语法大合集【附代码和超详细介绍以及使用】

JavaScript语法大合集 JavaScript引入到文件 嵌入到HTML文件中 <body><script>var num10;console.log(num);</script> </body>引入本地独立JS文件 <body><script src"./hello.js"></script> </body>引入网络来源…

leetcode:链表的中间结点

1.题目描述 题目链接&#xff1a;876. 链表的中间结点 - 力扣&#xff08;LeetCode&#xff09; 我们先看题目描述&#xff1a; 2.解题思路 我们用画图用快慢指针来解决这个问题 定义一个快指针fast&#xff0c;一个慢指针slow 快指针一次走两个结点&#xff0c;慢指针一次…

3GPP协议解读(一)_23.501_23.502_PDU Session_SMF与UDP的交互

UE发起计算服务申请后&#xff0c;网络侧处理的流程 UE发起服务的流程&#xff1a;service request网络侧处理服务涉及的通信数据通过PDU Session进行传输&#xff0c;涉及到SMF与UPF的交互。PDU Session的建立、管理全部由SMF&#xff08;Session Management Function&#x…

Docker与VM虚拟机的区别以及Docker的特点

01、本质上的区别 VM(VMware)在宿主机器、宿主机器操作系统的基础上创建虚拟层、虚拟化的操作系统、虚拟化的仓库&#xff0c;然后再安装应用&#xff1b; Container(Docker容器)&#xff0c;在宿主机器、宿主机器操作系统上创建Docker引擎&#xff0c;在引擎的基础上再安装应…

WordPress丸子小程序问题常见解决方案

WordPress丸子小程序问题常见解决方案 下载uniapp&#xff0c;导入项目。修改下图域名为自己的WP博客地址。&#xff08;如下图&#xff09; 发行微信小程序&#xff0c;如果显示不是项目所有者&#xff0c;请重新获取。 重新发行微信小程序&#xff0c;请打开微信开发者工具端…

【leaflet】学习笔记1-4

▒ 目录 ▒ &#x1f6eb; 导读开发环境 1️⃣ 改造greengis的leafletinsCodeinline-module服务器live-server 2️⃣ d1. 初见&#xff1a;Map、TileLayer说明/流程关键代码 3️⃣ d2. 多地图切换&#xff1a;Control.Layers说明/流程关键代码 4️⃣ d3. 标记&#xff1a;Marke…

【Proteus仿真】【51单片机】锂电池管理系统

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真51单片机控制器&#xff0c;使用LCD1602显示模块、DS18B20温度传感器、PCF8691 ADC模块、按键、LED蜂鸣器模块等。 主要功能&#xff1a; 系统运行后&#xff0c;LCD1602显示温度…

Git-概念与架构

GIT-概念与架构 一、背景和起源二、版本控制系统1.版本控制分类1.1 集中式版本控制1.2 分布式版本控制 2.Git和SVN对比2.1 SVN2.2 GIT 三、GIT框架1.工作区&#xff08;working directory&#xff09;2.暂存区&#xff08;staging area&#xff09;3.本地仓库&#xff08;local…

算法笔记-第五章-大整数运算

算法笔记-第五章-大整数运算 大整数运算大整数比较大整数加法大整数减法大整数乘法大整数乘法2大整数除法 大整数运算 一&#xff1a;使用数组存储整数的时候&#xff0c;整数的高位存储在数组的高位&#xff0c;整数的低位存储 在数组的低位 二&#xff1a;把整数按照字符串读…

除了chatGPT网站外,国内有些可以使用的AI网站 文心一言 讯飞星火 豆包 通义千问 人工智能网站 AI网站

2023年随着人工智能技术的不断发展&#xff0c;AI网站如ChatGPT等越来越受到人们的关注。这些网站具有多种作用&#xff0c;可以帮助人们更方便地获取信息、解决问题&#xff0c;甚至进行创作。 首先&#xff0c;AI网站可以提供智能问答服务。与传统的搜索引擎相比&#xff0c…