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

在这里插入图片描述

文章目录

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

🚩前言

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

🧩框架结构

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

文件编写通讯录,主要是多了文件读操作、写操作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;
}

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

树莓派5使用体验

原文地址&#xff1a;树莓派5使用体验 - Pleasure的博客 下面是正文内容&#xff1a; 前言 好久没有关于教程方面的博文了&#xff0c;由于最近打算入门嵌入式系统&#xff0c;所以就去购入了树莓派5开发板 树莓派5是2023年10月23日正式发售的&#xff0c;过去的时间不算太远吧…

XML文档节点导航与选择指南 | XPath基础知识

XPath&#xff08;XML Path Language&#xff09;是XSLT标准的主要组成部分。它用于在XML文档中浏览元素和属性&#xff0c;提供了一种强大的定位和选择节点的方式。 XPath的基本特点 代表XML路径语言&#xff1a; XPath是一种用于在XML文档中导航和选择节点的语言。 路径样式…

【CSS】新闻页面制作 案例一

&#xff08;大家好&#xff0c;今天我们将通过案例实战对之前学习过的CSS知识进行复习巩固&#xff0c;大家和我一起来吧&#xff0c;加油&#xff01;&#x1f495;&#xff09; 目录 一、前述 二、素材 案例文字素材 案例图片素材 三、案例分析 四、案例实施 五、应用…

Docker之镜像与容器的相关操作

目录 一、Docker镜像 搜索镜像 下载镜像 查看宿主机上的镜像 删除镜像 二、Docker容器 创建容器 查看容器 启停容器 删除容器 进入容器 创建/启动/进入容器 退出容器 查看容器内部信息 一、Docker镜像 Docker 运行容器前需要本地存在对应的镜像&#xff0c; 如…

安装包逆向2

import os import struct import lzma import hashlibDEBUG False # 调试标志 BASE_ADDRESS 0x00120200 # 基地址偏移量# Base类&#xff0c;用于存储基地址的数据 class Base:def __init__(self):self.startFilePos 0 # 基地址在文件中的起始位置self.data bytearray(0…

【蓝桥杯嵌入式】按键控制LED与LCD(必考三件套)

【蓝桥杯嵌入式】按键控制LED与LCD&#xff08;必考三件套&#xff09; 前言LED相关功能的实现LED基础功能函数&#xff08;点亮、全熄灭、翻转&#xff09;LED的闪烁与定时点亮熄灭流水灯的实现 按键的扫描及长短按、双击的实现按键的短按按键业务逻辑程序进程按键的长短按长短…

1995-2021年各省分品种能源产量和消费量数据

1995-2021年各省分品种能源产量和消费量数据 1、时间&#xff1a;1995-2021年 2、来源&#xff1a;能源统计年鉴、各省年鉴 3、指标&#xff1a;能源消费总量、煤炭消费量、焦炭消费量、原油消费量、汽油消费量、煤油消费量、柴油消费量、燃料油消费量、天然气消费量、电力消…

让智能体像孩子一样观察别人学习动作,跨视角技能学习数据集EgoExoLearn来了

ChatGPT狂飙160天&#xff0c;世界已经不是之前的样子。 新建了免费的人工智能中文站https://ai.weoknow.com 新建了收费的人工智能中文站https://ai.hzytsoft.cn/ 更多资源欢迎关注 在探索人工智能边界时&#xff0c;我们时常惊叹于人类孩童的学习能力 —— 可以轻易地将他人…

Unity学习笔记 - 第一个Hello World都算不上的项目

一、Unity安装 这里不细说安装了&#xff0c;首先需要Visual Studio&#xff0c;然后要安装Unity Hub&#xff0c;Unity Hub就像一个管理平台&#xff0c;安装完它之后&#xff0c;可以在它的界面上选择安装各个版本的编辑器。 开始您的创意项目并下载 Unity Hub | Unity通过 …

【Qt 学习笔记】Qt 中出现乱码的解释及讨论

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

Nginx配置之localhost和反向代理

文章目录 第一步、查看安装位置和配置文件第二步、web服务器设置第三步、localhost 指令第四步、设置反向代理 清明假期&#xff0c;在家练习Nginx配置&#xff0c;在前期【 linux环境下安装配置nginx代理服务器】已经完成nginx环境搭建&#xff0c;本期主要实践web服务器&…

副业选择攻略:如何找到最适合自己的那一个?

大家好&#xff0c;我是木薯。今天有个新人伙伴来咨询客服&#xff1a;新手适不适合在水牛社上做副业&#xff1f;什么样的副业适合自己&#xff1f; 这种问题其实对我们来说已经见得太多太多了&#xff0c;归其原因是因为自己对副业没有一个清晰的自我认知&#xff0c;从而感觉…

阿里千问大模型 Qwen1.5 开源 32B 模型,将开源进行到底!!!

阿里开源的千问系列模型&#xff0c;一直受到业界好评&#xff0c;之前版本有0.5B、1.8B、7B、14B、72B&#xff0c;但一直缺少的30B级别开源模型&#xff0c;这也一直是一个遗憾。 怎么说呢&#xff1f;72B模型太大&#xff0c;很多人用不起来&#xff0c;无论是微调&#xf…

基于JAVA+SSM+微信小程序+MySql+前后端分离的图书捐赠管理系统设计与实现

一、项目背景介绍&#xff1a; 在当今社会&#xff0c;图书捐赠是一种普遍而有益的行为&#xff0c;旨在促进阅读、教育和知识传播。图书捐赠可以帮助改善教育资源不足的地区、学校和社区的阅读环境&#xff0c;提供更多的学习机会和知识获取途径。随着互联网和移动技术的发展&…

pytorch交叉熵

目录 1. Entropy2. 交叉熵3. 二分类4. 为什么分类问题使用交叉熵5. 代码示例 1. Entropy Entropy中文是熵的意思&#xff0c;它代表一种不确定性&#xff0c;不确定性越高惊喜度也就越高。 如上图&#xff0c;假设熵代表中奖概率&#xff0c;当熵为2 的中奖概率为1/4没什么惊…

sharding‐jdbc之分库分表(mysql主从同步的数据库安装和使用)

水平分表 创建基础工程.. 引入sharding‐jdbc的maven依赖包 注意需要数据库连接池等依赖 <dependency><groupId>org.apache.shardingsphere</groupId><artifactId>sharding-jdbc-spring-boot-starter</artifactId><version>4.0.0-RC1&l…

1.0-spring入门

文章目录 前言一、版本要求二、第一个spring程序1.引入pom2.代码部分2.1 spring bean2.2 springContext.xml2.3 测试2.4 执行结果 总结 前言 最近想要系统的学习下spring相关的框架,于是乎,来到了B站(真是个好地方),spring会专门开一个专栏出来,记录学习心得,与大家共勉。 Spri…

51-37 由浅入深理解 Stable Diffusion 3

2024年3月5日&#xff0c;Stability AI公开Stable Diffusion 3论文&#xff0c;Scaling Rectified Flow Transformers for High-Resolution Image Synthesis。公司像往常一样承诺后续将开源代码&#xff0c;开源之光&#xff01;&#xff01;&#xff01; 在LDW潜在扩散模型论文…

缓存击穿以及解决方案

1.定义 缓存击穿问题也叫热点Key问题&#xff0c;就是一个被高并发访问并且缓存重建业务较复杂的key突然失效了&#xff0c;无数的请求访问会在瞬间给数据库带来巨大的冲击。 问题描述&#xff1a;假设线程1在查询缓存之后&#xff0c;本来应该去查询数据库&#xff0c;然后把…

8、滑动窗口-无重复字符的最长子串

解析&#xff1a; 遍历 判断map是否包含当前字符&#xff0c;如果包含&#xff1a; 获取重复的index下标在哪里获取len长度重新设置L指针,其中L指针不回退&#xff0c;也就是如果这个重复值在L前面那就忽略&#xff0c;如果是在后面那就设置为index1。 代码如下&#xff1a; …