练手项目层高阶3—《详解文件版本——通讯录管理系统》

news2024/11/20 9:47:24

在这里插入图片描述

文章目录

  • 🚩前言
    • 🧩框架结构
    • 📺效果展示
    • 🚀完整代码

🚩前言

我们前面写的两种方法(静态和动态),唯一缺点就是每次运行都要输入新的数据,很麻烦,也就是说写入的数据无法长久保存,代码运行结束后就立即释放了。所以,接下来就用文件操作的知识点,把写入的数据导入到文件中去。

🧩框架结构

由于我在前面的两篇文章中说了具体的项目需求,因此在这片当中我直接说编写代码的不同点。

文件编写通讯录,主要是多了文件读操作、写操作2个部分,下面就是这2个代码块,注意的就是文件记得即使关闭。

写操作,把数据录入到文件中去。

//文件写操作函数
void save_contact(ConSL* con)
{
	assert(con);
	FILE* pf_wirte = fopen("contact_data.txt", "wb");
	if (pf_wirte == NULL)
	{
		perror("save_contact fopen error!\n");
		return;
	}
	//写入 文件中
	for (int i = 0; i < con->size; i++)
	{
		fwrite(con->data+i, sizeof(PeoInfo), 1, pf_wirte);
		//把每个结构体类型中的信息写入到文件中去
	}
	printf("数据保存成功!\n");

	//关闭
	fclose(pf_wirte);
	pf_wirte = NULL;
}

读操作,把文件中的信息显示到控制台上。

//文件读操作函数
void load_contact(ConSL* con)
{
	PeoInfo temp = { 0 };//临时变量
	assert(con);
	FILE* pf_read = fopen("contact_data.txt", "rb");
	if (pf_read == NULL)
	{
		perror("load_contact fopen error!\n");
		return;
	}
	//循环读取文件中的内容
	while (fread(&temp,sizeof(PeoInfo),1,pf_read))//返回0的时候就读取完了
	{
		//读的时候,需要判断文件中的数据个数,在申请的空间中是否能存储完
		check_capacity(con);
		//用临时变量存储,再赋值给申请的空间中去
		con->data[con->size++] = temp;
	}
	//记得关闭文件
	fclose(pf_read);
	pf_read = NULL;
}

📺效果展示

直接显示数据,就可以查看文件中的信息了

在这里插入图片描述

🚀完整代码

Contact.h头文件

#pragma once
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<conio.h>
#include<Windows.h>

#define NAME_MAX 100
#define AGE_MAX 3
#define SEX_MAX 4
#define TEL_MAX 20
#define ADDR_MAX 40

//枚举功能
enum address_book
{
	Exit,
	Add,
	Delete,
	Find,
	Modify,
	Sort,
	Show,
	Save
};

//通讯录联系人信息
typedef struct Person
{
	char Name[NAME_MAX];
	char Age[AGE_MAX];
	char Gender[SEX_MAX];
	char Tel[TEL_MAX];
	char Address[ADDR_MAX];
}PeoInfo;



//顺序表结构体
typedef struct contact_seq_list
{
	PeoInfo* data;
	int capacity;//空间容量大小
	int size;//有效元素个数
}ConSL;



void init_contact(ConSL* con);//初始化函数

void load_contact(ConSL* con);//文件读操作函数

void save_contact(ConSL* con);//文件写操作函数

void addition_contact(ConSL* con);//添加函数

void delete_contact(ConSL* con);//删除函数

void show_contact(ConSL* con);//打印函数

void find_contact(ConSL* con);//查找函数

void modify_contact(ConSL* con);//修改函数

void sort_contact(ConSL* con);//排序函数

void save_contact(ConSL* con);//保存函数

void destroy_contact(ConSL* con);//销毁函数

Contact.c源文件

#define _CRT_SECURE_NO_WARNINGS 1

#include "Contact.h"

void check_capacity(ConSL* ptr);//声明一下

//文件读操作函数
void load_contact(ConSL* con)
{
	PeoInfo temp = { 0 };//临时变量
	assert(con);
	FILE* pf_read = fopen("contact_data.txt", "rb");
	if (pf_read == NULL)
	{
		perror("load_contact fopen error!\n");
		return;
	}
	//循环读取文件中的内容
	while (fread(&temp,sizeof(PeoInfo),1,pf_read))//返回0的时候就读取完了
	{
		check_capacity(con);
		con->data[con->size++] = temp;
	}

	fclose(pf_read);
	pf_read = NULL;
}


//文件写操作函数
void save_contact(ConSL* con)
{
	assert(con);
	FILE* pf_wirte = fopen("contact_data.txt", "wb");
	if (pf_wirte == NULL)
	{
		perror("save_contact fopen error!\n");
		return;
	}
	//写入 文件中
	for (int i = 0; i < con->size; i++)
	{
		fwrite(con->data+i, sizeof(PeoInfo), 1, pf_wirte);
	}
	printf("数据保存成功!\n");

	//关闭
	fclose(pf_wirte);
	pf_wirte = NULL;
}


//初始化函数
void init_contact(ConSL* con)
{
	con->data = NULL;
	con->capacity = con->size = 0;
	//文件加载
	load_contact(con);
}


void check_capacity(ConSL* ptr)
{
	if (ptr->capacity == ptr->size)
	{
		//说明空间为空或者满了,则需要扩容
		int new_capacity = ptr->capacity == 0 ? 4 : 2 * ptr->capacity;
		PeoInfo* temp = (PeoInfo*)realloc(ptr->data, new_capacity * sizeof(PeoInfo));
		if (temp == NULL)
		{
			perror("realloc fail!");
			exit(1);
		}
		ptr->data = temp;
		ptr->capacity = new_capacity;
	}
}


//添加函数
void addition_contact(ConSL* con)
{
	assert(con);
	//添加时必须判断是否满
	check_capacity(con);
	//添加数据
	printf("联系人信息录入中……\n");
	printf("请输入姓名:");
	scanf("%s", con->data[con->size].Name);
	printf("请输入年龄:");
	scanf("%s", con->data[con->size].Age);
	printf("请输入性别:");
	scanf("%s", con->data[con->size].Gender);
	printf("请输入电话:");
	scanf("%s", con->data[con->size].Tel);
	printf("请输入地址:");
	scanf("%s", con->data[con->size].Address);

	//元素个数自增
	con->size++;
	printf("添加成功!\n");
}


//打印函数
void show_contact(ConSL* con)
{
	//assert(con.size);
	if (con->size == 0)
	{
		printf("通讯录为空,无法显示!\n");
		return;
	}
	printf("通讯录总人数:%d\n", con->size);
	printf("*************************************************************************************************\n");
	printf("*****************************          通讯录信息         ***************************************\n");
	printf("*************************************************************************************************\n");
	printf("-------------------------------------------------------------------------------------------------\n");
	printf("|%-12s\t%-3s\t%-4s\t%-12s\t\t%-40s|\n", "姓名", "年龄", "性别", "电话", "地址");
	for (int i = 0; i < con->size; i++)
	{
		printf("|%-12s\t%-3s\t%-4s\t%-12s\t\t%-40s|\n", con->data[i].Name
			, con->data[i].Age
			, con->data[i].Gender
			, con->data[i].Tel
			, con->data[i].Address);
	}
	printf("-------------------------------------------------------------------------------------------------\n");
}


static int find_information(ConSL* ptr,char* name)
{
	for (int i = 0; i < ptr->size; i++)
	{
		if (strcmp(ptr->data[i].Name, name) == 0)
		{
			return i;
		}
	}
	return -1;
}


//删除函数
void delete_contact(ConSL* con)
{
	//assert(con&&con->size);
	assert(con);
	if (con->size == 0)
	{
		printf("通讯录为空,无法删除!\n");
		return;
	}
	printf("请输入要删除的联系人的姓名:\n");
	char name[NAME_MAX];
	scanf("%s", name);
	int ret=find_information(con, name);
	if (ret == -1)
	{
		printf("没找到!\n");
		return;
	}
	for (int i = ret; i < con->size - 1; i++)
	{
		con->data[i] = con->data[i + 1];
	}
	con->size--;
	printf("删除成功!\n");
	show_contact(con);
}


//查找函数
void find_contact(ConSL* con)
{
	assert(con);
	if (con->size == 0)
	{
		printf("通讯录为空,无法查找!\n");
		return;
	}
	printf("请输入要查找的联系人的姓名:\n");
	char name[NAME_MAX];
	scanf("%s", name);
	int ret=find_information(con, name);
	if (ret == -1)
	{
		printf("没查到!\n");
		return;
	}
	printf("-------------------------------------------------------------------------------------------------\n");
	printf("|%-12s\t%-3s\t%-4s\t%-12s\t\t%-40s|\n", "姓名", "年龄", "性别", "电话", "地址");
	printf("|%-12s\t%-3s\t%-4s\t%-12s\t\t%-40s|\n", con->data[ret].Name
		, con->data[ret].Age
		, con->data[ret].Gender
		, con->data[ret].Tel
		, con->data[ret].Address);
	printf("-------------------------------------------------------------------------------------------------\n");
}


//修改函数
void modify_contact(ConSL* con)
{
	assert(con);
	if (con->size == 0)
	{
		printf("通讯录为空,无法修改!\n");
		return;
	}
	printf("请输入要修改的联系人的姓名:\n");
	char name[NAME_MAX];
	scanf("%s", name);
	int ret = find_information(con, name);
	if (ret == -1)
	{
		printf("没找到,无法修改!\n");
		return;
	}
	printf("修改进行中………\n");
	printf("请输入新的姓名:");
	scanf("%s", con->data[ret].Name);
	printf("请输入新的年龄:");
	scanf("%s", con->data[ret].Age);
	printf("请输入新的性别:");
	scanf("%s", con->data[ret].Gender);
	printf("请输入新的电话:");
	scanf("%s", con->data[ret].Tel);
	printf("请输入新的地址:");
	scanf("%s", con->data[ret].Address);

	printf("修改成功!\n");
	show_contact(con);
}



int compar_by_name(const void* e1, const void* e2)
{
	return strcmp(((PeoInfo*)e1)->Name, ((PeoInfo*)e2)->Name);
}

int compar_by_age(const void* e1, const void* e2)
{
	return strcmp(((PeoInfo*)e1)->Age, ((PeoInfo*)e2)->Age);
}


//排序函数
void sort_contact(ConSL* con)
{
	assert(con);
	if (con->size == 0)
	{
		printf("通讯录为空,无法排序!\n");
		return;
	}

	printf("请选择排序方式:1、按照姓名排序,2、按照年龄排序。\n");
	int select1 = 0;
	scanf("%d", &select1);
	if (select1 == 1)
	{
		qsort(con->data, con->size, sizeof(PeoInfo), compar_by_name);
		printf("排序成功!\n");
	}
	if (select1 == 2)
	{
		qsort(con->data, con->size, sizeof(PeoInfo), compar_by_age);
		printf("排序成功!\n");
	}


}


//销毁函数
void destroy_contact(ConSL* con)
{
	if (con->data)
	{
		free(con->data);
	}
	con->data = NULL;
}

test_contact.c源文件

#define _CRT_SECURE_NO_WARNINGS 1
#include"Contact.h"

void menu()
{
	printf("\t\t\t\t\t***************************************\n");
	printf("\t\t\t\t\t*********        通讯录       *********\n");
	printf("\t\t\t\t\t***************************************\n");
	printf("\t\t\t\t\t****  ——>  1、添加联系人  <——  ****\n");
	printf("\t\t\t\t\t***************************************\n");
	printf("\t\t\t\t\t****  ——>  2、删除联系人  <——  ****\n");
	printf("\t\t\t\t\t***************************************\n");
	printf("\t\t\t\t\t****  ——>  3、查找联系人  <——  ****\n");
	printf("\t\t\t\t\t***************************************\n");
	printf("\t\t\t\t\t****  ——>  4、修改联系人  <——  ****\n");
	printf("\t\t\t\t\t***************************************\n");
	printf("\t\t\t\t\t****  ——>  5、通讯录排序  <——  ****\n");
	printf("\t\t\t\t\t***************************************\n");
	printf("\t\t\t\t\t****  ——>  6、显示联系人  <——  ****\n");
	printf("\t\t\t\t\t***************************************\n");
	printf("\t\t\t\t\t****  ——>  7、保存联系人  <——  ****\n");
	printf("\t\t\t\t\t***************************************\n");
	printf("\t\t\t\t\t****  ——>  0、退出通讯录  <——  ****\n");
	printf("\t\t\t\t\t***************************************\n");

}


void test()
{
	ConSL con;
	init_contact(&con);
	int input = 0;
	while (1)
	{
		menu();
		printf("请选择功能:\n");
		scanf("%d", &input);
		switch (input)
		{
		case Exit:
			save_contact(&con);
			destroy_contact(&con);
			printf("欢迎下次使用!\n");
			exit(1);
		case Add:
			addition_contact(&con);
			break;
		case Delete:
			delete_contact(&con);
			break;
		case Find:
			find_contact(&con);
			break;
		case Modify:
			modify_contact(&con);
			break;
		case Sort:
			sort_contact(&con);
			break;
		case Show:
			show_contact(&con);
			break;
		case Save:
			save_contact(&con);
			break;
		default:
			printf("选择错误,请重新选择:\n");
			break;
		}
		_getch();
		system("cls");
	}
}

int main()
{
	test();
	return 0;
}

文件版本的通讯录到此为止。🤞
在这里插入图片描述

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

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

相关文章

C# 使用共享文件生成项目

项目文件中添加共享文件 <ItemGroup><Compile Include"..\Shared\Interfaces\Services\ITextService.cs" Link"Interfaces\Services\ITextService.cs" /><Compile Include"..\Shared\Services\TextService.cs" Link"Service…

[StartingPoint][Tier1]Sequel

Task 1 During our scan, which port do we find serving MySQL? (在扫描过程中&#xff0c;我们发现哪个端口为 MySQL 提供服务&#xff1f;) 3306 Task 2 What community-developed MySQL version is the target running? (目标正在运行哪个社区开发的 MySQL 版本&…

vue2/vue3手写专题——实现父子组件通信、祖先通信的方法

Vue 组件通信可以使用以下几种方法&#xff1a; 父组件向子组件传递数据&#xff1a;使用 props 将数据从父组件传递给子组件&#xff0c;子组件可以通过 props 接收和使用数据。子组件向父组件传递数据&#xff1a;使用 $emit 触发自定义事件&#xff0c;父组件可以通过事件监…

【Kaggle】练习赛《鲍鱼年龄预测》(上)

前言 上一篇文章&#xff0c;讲解了《肥胖风险的多类别预测》机器学习方面的文章&#xff0c;主要是多分类算法的运用&#xff0c;本文是一个回归的算法&#xff0c;本期是2024年4月份的题目《Regression with an Abalone Dataset》即《鲍鱼年龄预测》&#xff0c;在此分享高手…

Vuex的模块化管理

1&#xff1a;定义一个单独的模块。由于mutation的第二个参数只能提交一个对象&#xff0c;所以这里的ThisLog是个json串。 2&#xff1a;在Vuex中的index.js中引入该模块 3&#xff1a;在别的组件中通过...mapState调用模块保存的State的值。 4&#xff1a;用...mapMutations修…

K8S之Job和CronJob控制器

这里写目录标题 Job概念适用场景使用案例 CronJob概念适用场景使用案例 Job 概念 Job控制器用于管理Pod对象运行一次性任务&#xff0c;例如&#xff1a;对数据库备份&#xff0c;可以直接在k8s上启动一个mysqldump备份程序&#xff0c;也可以启动一个pod&#xff0c;这个pod…

LRU的原理与实现(java)

介绍 LRU的英文全称为Least Recently Used&#xff0c;即最近最少使用。它是一种内存数据淘汰算法&#xff0c;当添加想要添加数据而内存不足时&#xff0c;它会优先将最近一段时间内使用最少的数据淘汰掉&#xff0c;再将数据添加进来。 原理 LRU的原理在介绍中就已经基本说…

C++之类和对象(上)

目录 1.面向过程和面向对象初步认识 2.类的引入 3.类的定义 4.类的访问限定符及封装 4.1访问限定符 4.2 类的两种定义方式 第一种&#xff1a; 第二种&#xff1a; 4.3封装 5.类的实例化 6.类对象模型 1.面向过程和面向对象初步认识 C语言是面向过程的&#xff0c;…

华为汽车的“计算+通信”电子电气架构

文章目录 整车结构 硬件平台 软件平台 总结展望 整车EEA&#xff08;电子电气架构&#xff09;&#xff0c;按照博世提出的演进路径&#xff0c;大致可以划分为四个阶段&#xff1a;分布式模块阶段、区域控制阶段、中央计算阶段、云计算阶段。示例如下&#xff1a; 本文选取…

Java8 进阶

Java8 进阶 文章目录 Java8 进阶什么是函数式接口&#xff1f;public interface Supplierpublic interface Consumerpublic interface Predicatepublic interface FunctionJava8 特性总结&#xff1a;一、Function<T, R>二、Consumer<T>三、Supplier<T>四、P…

BUUCTF:BUU UPLOAD COURSE 1[WriteUP]

构造一句话PHP木马 <?php eval(system($_POST[shell])); ?> 利用eval函数解析$shell的值使得服务器执行system命令 eval函数是无法直接执行命令的&#xff0c;只能把字符串当作php代码解析 这里我们构造的木马是POST的方式上传&#xff0c;那就用MaxHacKBar来执行 …

分布式锁实战

4、分布式锁 4.1 、基本原理和实现方式对比 分布式锁&#xff1a;满足分布式系统或集群模式下多进程可见并且互斥的锁。 分布式锁的核心思想就是让大家都使用同一把锁&#xff0c;只要大家使用的是同一把锁&#xff0c;那么我们就能锁住线程&#xff0c;不让线程进行&#x…

springBoot--阿里云短信验证

阿里云短信验证 前言阿里云短信服务免费领取100条短信服务1、开通短信服务2、申请签名3、申请模板4、通过子用户获取账号的AccessKey ID 和AccessKey Secret5、使用教程 前言 在我们平时登录中短信验证吗验证在当今是必不可少的&#xff0c;下面是基于阿里云开发的短信验证操作…

【Qt 学习笔记】详解Qt中的信号和槽

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;Qt 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ 详解Qt中的信号与槽 文章编号&#xff1a;Qt 学习笔记 / 12 文章目录…

【数据结构】ArrayList详解

目录 前言 1. 线性表 2. 顺序表 3. ArrayList的介绍和使用 3.1 语法格式 3.2 添加元素 3.3 删除元素 3.4 截取部分arrayList 3.5 其他方法 4. ArrayList的遍历 5.ArrayList的扩容机制 6. ArrayList的优缺点 结语 前言 在集合框架中&#xff0c;ArrayList就是一个…

代码随想录第19天

654. 最大二叉树 已解答 中等 相关标签 相关企业 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点&#xff0c;其值为 nums 中的最大值。递归地在最大值 左边 的 子数组前缀上 构建左子树。递归地在最大值 右边 的 子数组后缀…

Mac 配置 Aria2

文章目录 1. Aria2 安装1.1 安装 brew1.2 安装 Aria2 2. 配置 Aria22.1 创建配置文件 aria2.conf 和空对话文件 aria2.session2.2 编辑配置文件 aria2.conf 3. 开机启动设置3.1 创建用户启动文件3.2 管理自启动项 4. 配置 BT tracker 自动更新4.1 XIU2/TrackersListCollection …

通义灵码-ai编码

https://developer.aliyun.com/topic/lingma/activities/202403?taskCode14508&recordIdb1ef3ba27250a5818b1b6ffe418af658#/?utm_contentm_fission_1 「通义灵码 体验 AI 编码&#xff0c;开 AI 盲盒」

sourcetree提交代码出现闪退报错(已解决)

当我在sourcetree提交代码时&#xff0c;点击提交按钮出现闪退关闭&#xff0c;并弹出下面的报错框&#xff0c;报错的图片如下&#xff1a; 那么经过了解&#xff0c;出现这样的报错原因是&#xff0c;git的提交时无法定位提交的人是谁&#xff0c;导致无法提交 那么解决的方…

Allavsoft for Mac v3.27.0.8852注册激活版 优秀的视频下载工具

Allavsoft for Mac是一款功能强大的多媒体下载和转换工具&#xff0c;支持从各种在线视频网站和流媒体服务下载视频、音频和图片。它具备批量下载和转换功能&#xff0c;可将文件转换为多种格式&#xff0c;以适应不同设备的播放需求。此外&#xff0c;Allavsoft还提供视频编辑…