【C语言】优化通讯录管理系统2

news2024/11/24 20:21:20

本篇博客是基于上一篇博客写出来的,了解上一篇博客

大家好,我是苏貝,本篇博客带大家再次优化上一篇的通讯录,实现将录入的数据在程序退出后存储到文件中,在下一次程序开始时打开文件获取数据,如果你觉得我写的还不错的话,可以给我一个赞👍吗,感谢❤️
在这里插入图片描述


目录

  • 一. 保存通讯录到文件中
  • 二. 在程序开始时加载文件信息到通讯录
  • 三. 模块化代码实现
    • contact.c
    • test.c
    • contact.h
    • 结果演示

一. 保存通讯录到文件中

既然我们想在程序退出后将数据存储在文件中,那么在选择退出程序选项时,要实现SaveContact函数,它的功能就是保存通讯录到文件中

case EXIT:
			printf("退出程序\n");
			//保存通讯录到文件中
			SaveContact(&con);
			DestroyContact(&con);
			break;

想要保存通讯录到文件中,首先需要打开一个文件,以“wb”形式打开文件,若文件存在,则直接打开文件。如文件不存在,则先建立该文件并打开。需要判断打开文件是否成功。成功后开始将数据写入文件中,使用fwrite二进制输出函数(将数据写入流中)了解fwrite函数
使用fwrite(&(pc->data[i]), sizeof(PeoInfo), 1, pf);或者fwrite(pc->data + i, sizeof(PeoInfo), 1, pf); 将一组数据写入流中,循环pc->sz次,可以将所有的数据都写入文件(因为每次使用完fwrite函数读取n个元素后,函数的指示器会向后移n个元素,即下次调用fwrite函数时,是从第n+1个元素开始读取的)

void SaveContact(Contact* pc) 
{
	FILE* pf = fopen("contact.txt", "wb");
	if (pf == NULL)
	{
		perror("SaveContact");
		return;
	}
	//写文件
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		//fwrite(&(pc->data[i]), sizeof(PeoInfo), 1, pf);
		fwrite(pc->data + i, sizeof(PeoInfo), 1, pf);
	}
	fclose(pf);
	pf = NULL;
}

二. 在程序开始时加载文件信息到通讯录

我们想要在程序开始时就读取文件中的通讯录,那么不妨将LoadContact(pc)函数放在初始化通讯录函数的最后。

//动态初始化通讯录
void InitContact(Contact* pc)
{
	assert(pc);
	pc->sz = 0;
	pc->capacity = DEFAULT_CAP;
	pc->data = (PeoInfo*)calloc(pc->capacity, sizeof(PeoInfo));
	if (pc->data == NULL)
	{
		perror("InitContact_calloc");
		return;
	}
	LoadContact(pc);
}

要读取文件,那么首先要打开文件,再判断是否打开成功,最后关闭文件。成功打开文件后,读取文件。因为前面是用fwrite函数将数据写入文件中,所以现在要用fread函数读取文件中的数据。用fread函数每次读取一个联系人的数据,读取成功,函数返回1,进去while循环,将tmp赋值给通讯录的元素,下标是pc->sz,最后sz++;读取失败,函数返回0,退出while循环。

    PeoInfo tmp = { 0 };
	while (fread(&tmp, sizeof(PeoInfo), 1, pf))
	{
		pc->data[pc->sz] = tmp;
		pc->sz++;
	}

你觉得这就好了吗?不是的,在将tmp赋值给通讯录前,我们要先判断通讯录的大小是否小于通讯录的最大容量,最大容量的初始值是3(如下),如果文件中的元素>=3,我们在进行赋值操作前就要先增容。

#define DEFAULT_CAP 3

增容的代码在动态增加联系人中,因为现在我们又需要增容操作,所以将增容的代码提取出来作为一个函数使用

//动态增加联系人
void AddContact(Contact* pc)
{
	assert(pc);
	//增容
	if (pc->sz == pc->capacity)
	{
		PeoInfo* tmp = realloc(pc->data, (pc->capacity + DEFAAULT_INI) * sizeof(PeoInfo));
		if (tmp == NULL)
		{
			perror("AddContact_realloc");
			return;
		}
		pc->data = tmp;
		pc->capacity += DEFAAULT_INI;
		printf("增容成功\n");
	}
	
	printf("请输入名字:");
	scanf("%s", pc->data[pc->sz].name);
	printf("请输入年龄:");
	scanf("%d", &(pc->data[pc->sz].age));
	printf("请输入性别:");
	scanf("%s", pc->data[pc->sz].gender);
	printf("请输入电话:");
	scanf("%s", pc->data[pc->sz].tele);
	printf("请输入地址:");
	scanf("%s", pc->data[pc->sz].addr);

	pc->sz++;
	printf("增加成功\n");
}
void CheckCapacity(Contact* pc)
{
	if (pc->sz == pc->capacity)
	{
		PeoInfo* tmp = realloc(pc->data, (pc->capacity + DEFAAULT_INI) * sizeof(PeoInfo));
		if (tmp == NULL)
		{
			perror("AddContact_realloc");
			return;
		}
		pc->data = tmp;
		pc->capacity += DEFAAULT_INI;
		printf("增容成功\n");
	}
}

还有一个问题,为什么要定义一个变量tmp来接收文件的数据而不是直接用pc->data[pc->sz]来接收,这也是为了避免通讯录容量不够而导致的错误

void LoadContact(Contact* pc)
{
	FILE* pf = fopen("contact.txt", "rb");
	if (pf == NULL)
	{
		perror("LoadContact");
		return;
	}
	//读文件
	PeoInfo tmp = { 0 };
	while (fread(&tmp, sizeof(PeoInfo), 1, pf))
	{
		CheckCapacity(pc);
		pc->data[pc->sz] = tmp;
		pc->sz++;
	}

	fclose(pf);
	pf = NULL;
}

三. 模块化代码实现

contact.c

#include"contact.h"
//静态初始化通讯录
//void InitContact(Contact* pc)
//{
//	assert(pc);
//	pc->sz = 0;
//	memset(pc->data, 0, sizeof(pc->data));
//}

void CheckCapacity(Contact* pc);

void LoadContact(Contact* pc)
{
	FILE* pf = fopen("contact.txt", "rb");
	if (pf == NULL)
	{
		perror("LoadContact");
		return;
	}
	//读文件
	PeoInfo tmp = { 0 };
	while (fread(&tmp, sizeof(PeoInfo), 1, pf))
	{
		CheckCapacity(pc);
		pc->data[pc->sz] = tmp;
		pc->sz++;
	}

	fclose(pf);
	pf = NULL;

}

//动态初始化通讯录
void InitContact(Contact* pc)
{
	assert(pc);
	pc->sz = 0;
	pc->capacity = DEFAULT_CAP;
	pc->data = (PeoInfo*)calloc(pc->capacity, sizeof(PeoInfo));
	if (pc->data == NULL)
	{
		perror("InitContact_calloc");
		return;
	}
	LoadContact(pc);
}

//静态增加联系人
//void AddContact(Contact* pc)
//{
//	assert(pc);
//	if (pc->sz == MAX)
//	{
//		printf("通讯录已满,增加失败\n");
//		return;
//	}
//	printf("请输入名字:");
//	scanf("%s",pc->data[pc->sz].name );
//	printf("请输入年龄:");
//	scanf("%d", &(pc->data[pc->sz].age));
//	printf("请输入性别:");
//	scanf("%s", pc->data[pc->sz].gender);
//	printf("请输入电话:");
//	scanf("%s", pc->data[pc->sz].tele);
//	printf("请输入地址:");
//	scanf("%s", pc->data[pc->sz].addr);
//
//	pc->sz++;
//	printf("增加成功\n");
//}

void CheckCapacity(Contact* pc)
{
	if (pc->sz == pc->capacity)
	{
		PeoInfo* tmp = realloc(pc->data, (pc->capacity + DEFAAULT_INI) * sizeof(PeoInfo));
		if (tmp == NULL)
		{
			perror("AddContact_realloc");
			return;
		}
		pc->data = tmp;
		pc->capacity += DEFAAULT_INI;
		printf("增容成功\n");
	}
}

//动态增加联系人
void AddContact(Contact* pc)
{
	assert(pc);
	//增容
	CheckCapacity(pc);
	printf("请输入名字:");
	scanf("%s", pc->data[pc->sz].name);
	printf("请输入年龄:");
	scanf("%d", &(pc->data[pc->sz].age));
	printf("请输入性别:");
	scanf("%s", pc->data[pc->sz].gender);
	printf("请输入电话:");
	scanf("%s", pc->data[pc->sz].tele);
	printf("请输入地址:");
	scanf("%s", pc->data[pc->sz].addr);

	pc->sz++;
	printf("增加成功\n");
}


int FindOfName(char* name, Contact* pc)
{
	assert(name && pc);
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		if (0 == strcmp(name, (pc->data[i].name)))
			return i;
	}
	return -1;
}

//删除联系人
void DelContact(Contact* pc)
{
	assert(pc);
	char name[NAME_MAX] = { 0 };
	if (pc->sz == 0)
	{
		printf("通讯录为空,删除失败\n");
		return;
	}
	printf("请输入要删除的人的名字:");
	scanf("%s", name);
	int ret = FindOfName(name, pc);
	if (ret == -1)
	{
		printf("找不到要删除的人\n");
		return;
	}
	int i = 0;
	for (i = ret; i < pc->sz - 1; i++)
	{
		pc->data[i] = pc->data[i + 1];
	}
	pc->sz--;
	printf("删除成功\n");
}

//打印通讯录
void ShowContact(Contact* pc)
{
	assert(pc);
	if (pc->sz == 0)
	{
		printf("通讯录为空,打印无意义\n");
		return;
	}
	int i = 0;
	printf("%-20s%-5s%-5s%-30s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	for (i = 0; i < pc->sz; i++)
	{
		printf("%-20s%-5d%-5s%-30s%-30s\n", pc->data[i].name, pc->data[i].age,
			pc->data[i].gender, pc->data[i].tele, pc->data[i].addr);
	}
}



//查找联系人
void SelectContact(Contact* pc)
{
	char name[NAME_MAX] = { 0 };
	printf("请输入要查找的人的名字:");
	scanf("%s", name);
	int ret = FindOfName(name, pc);
	if (ret == -1)
	{
		printf("找不到要查找的人\n");
		return;
	}
	printf("%-20s%-5s%-5s%-30s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");
	printf("%-20s%-5d%-5s%-30s%-30s\n", pc->data[ret].name, pc->data[ret].age,
		pc->data[ret].gender, pc->data[ret].tele, pc->data[ret].addr);
}



//修改联系人信息
void ModifyContact(Contact* pc)
{
	assert(pc);
	char name[NAME_MAX] = { 0 };
	printf("请输入要修改的人的名字:");
	scanf("%s", name);
	int ret = FindOfName(name, pc);
	if (ret == -1)
	{
		printf("找不到要修改的人\n");
		return;
	}
	printf("请输入名字:");
	scanf("%s", pc->data[ret].name);
	printf("请输入年龄:");
	scanf("%d", &(pc->data[ret].age));
	printf("请输入性别:");
	scanf("%s", pc->data[ret].gender);
	printf("请输入电话:");
	scanf("%s", pc->data[ret].tele);
	printf("请输入地址:");
	scanf("%s", pc->data[ret].addr);
}


int cmp(const void* a, const void* b)
{
	return strcmp((char*)a, (char*)b);
}


//以名字排序所有联系人
void SortContact(Contact* pc)
{
	assert(pc);
	qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp);
	printf("排序成功\n");
}


//销毁通讯录
void DestroyContact(Contact* pc)
{
	free(pc->data);
	pc->data = NULL;
}

void SaveContact(Contact* pc) 
{
	FILE* pf = fopen("contact.txt", "wb");
	if (pf == NULL)
	{
		perror("SaveContact");
		return;
	}
	//写文件
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
		//fwrite(&(pc->data[i]), sizeof(PeoInfo), 1, pf);
		fwrite(pc->data + i, sizeof(PeoInfo), 1, pf);
	}
	fclose(pf);
	pf = NULL;
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1

#include"contact.h"

void menu()
{
	printf("-----------------------------------\n");
	printf("***********************************\n");
	printf("******  1.Add       2.Del    ******\n");
	printf("******  3.Select    4.Modify ******\n");
	printf("******  5.Show      6.sort   ******\n");
	printf("******  0.exit               ******\n");
	printf("***********************************\n");
	printf("-----------------------------------\n");
}

enum Option
{
	EXIT,
	ADD,
	DEL,
	SELECT,
	MODIFY,
	SHOW,
	SORT
};

int main()
{
	Contact con;
	//初始化通讯录
	InitContact(&con);
	int input = 0;
	do
	{ 
		menu();
		printf("请选择:");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			AddContact(&con);
			break;
		case DEL:
			DelContact(&con);
			break;
		case SELECT:
			SelectContact(&con);
			break;
		case MODIFY:
			ModifyContact(&con);
			break;
		case SHOW:
			ShowContact(&con);
			break;
		case SORT:
			SortContact(&con);
			break;
		case EXIT:
			printf("退出程序\n");
			//保存通讯录到文件中
			SaveContact(&con);
			DestroyContact(&con);
			break;
		default:
			printf("选择错误,请重新选择\n");
			break;
		}
	} while (input);
	return 0;
}

contact.h

#pragma once

#include<stdio.h>
#include<assert.h>
#include<string.h>
#include<stdlib.h>


#define NAME_MAX 20
#define GENDER_MAX 5
#define TELE_MAX 12
#define ADDR_MAX 30

//#define MAX 1000

#define DEFAULT_CAP 3
#define DEFAAULT_INI 2


typedef struct PeoInfo
{
	char name[NAME_MAX];
	int age;
	char gender[GENDER_MAX];
	char tele[TELE_MAX];
	char addr[ADDR_MAX];
}PeoInfo;


//静态版本
//typedef struct Contact
//{
//	PeoInfo data[MAX];
//	int sz;
//}Contact;


//动态版本
typedef struct Contact
{
	PeoInfo *data;
	int sz;//当前通讯录中存放的人的信息的个数
	int capacity;//通讯录的容量
}Contact;


//初始化通讯录
void InitContact(Contact* pc);

//增加联系人
void AddContact(Contact* pc);

//删除联系人
void DelContact(Contact* pc);

//打印通讯录
void ShowContact(Contact* pc);

//查找联系人
void SelectContact(Contact* pc);

//修改联系人信息
void ModifyContact(Contact* pc);

//以名字排序所有联系人
void SortContact(Contact* pc);

//销毁通讯录
void DestroyContact(Contact* pc);

//判断是否需要增容
void CheckCapacity(Contact* pc);

//保存通讯录到文件中
void SaveContact(Contact* pc);

//初始化时读取文件
void LoadContact(Contact* pc);


结果演示

第一次运行程序
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
第二次运行程序
在程序运行时就加载文件信息到通讯录,因为文件中有4个联系人的信息,所以显示增容成功
在这里插入图片描述


好了,那么本篇博客就到此结束了,如果你觉得本篇博客对你有些帮助,可以给个大大的赞👍吗,感谢看到这里,我们下篇博客见❤️

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

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

相关文章

耶鲁博弈论笔记

编辑记录&#xff1a; 1126&#xff1a;开个新坑&#xff0c;耶鲁大学的博弈论课程&#xff0c; 和专业相关不大&#xff0c;纯兴趣&#xff0c;尽量写好一点吧 1. 首先指出博弈论是一种研究策略形式的方法&#xff0c;对于经济学中&#xff0c;完全竞争市场只能被动接受均衡…

浏览器中实现可视化的方式有哪几种?带你盘点一下

前言 &#x1f4eb; 大家好&#xff0c;我是南木元元&#xff0c;热衷分享有趣实用的文章&#xff0c;希望大家多多支持&#xff0c;一起进步&#xff01; &#x1f345; 个人主页&#xff1a;南木元元 目录 可视化的含义 浏览器中实现可视化的4种方式 1. HTMLCSS 2. SVG …

鱼哥赠书活动第④期:从0到1Python进阶《利用Python进行数据分析》让你学完成为Python大神!!!

鱼哥赠书活动第④期&#xff1a; 《利用Python进行数据分析》、作译者简介&#xff1a;主要变动&#xff1a;购书链接&#xff1a; 适合阅读对象&#xff1a;赠书抽奖规则:往期赠书福利&#xff1a; 《利用Python进行数据分析》、 Python 语言极具吸引力。自从 1991 年诞生以来…

Linux中Netstat命令最常用的五个用法

当涉及到网络故障排除和网络连接监控时&#xff0c;netstat命令是Linux系统中一个非常常用的工具。netstat命令用于显示与网络相关的统计数据以及网络连接信息。无论是检查网络连接状态、监视网络接口还是查找网络服务的使用情况&#xff0c;netstat命令都能提供有用的信息。在…

视频后期效果制作工具Mocha Pro 2022 Plugins mac中文版软件介绍

Mocha Pro 2022 mac是一款专业的三维摄像机反求摩卡跟踪插件&#xff0c;同时也是一款视频后期效果制作工具&#xff0c;Mocha Pro 2022下载能够给数字媒体艺术家提供强大的、直观的和创新的追踪解决方案用简化的界面、加速的工作流程以及轻松追踪和操作镜头的强大性&#xff0…

conda环境下module ‘PIL.Image‘ has no attribute ‘ANTIALIAS‘

1 问题描述 在训练语音模型时&#xff0c;出现如下错误&#xff1a; Traceback (most recent call last):File "/opt/Bert-VITS2-2.0.2.1/train_ms.py", line 660, in <module>run()File "/opt/Bert-VITS2-2.0.2.1/train_ms.py", line 282, in run…

2023-11-27 事业-代号s-独立站选品工具-记录

摘要: 2023-11-27 事业-代号s-独立站选品工具-记录 选品工具 1. Amazon best seller ‍ 当我们最开始接触选品的时候&#xff0c;最基础也是最重要的选品方法就是Best Seller选品法。 ‍ Best Sellers榜单是每位亚马逊卖家都十分熟悉的&#xff0c;这个榜单是亚马逊基于li…

【【Linux下的Petallinux 以及其他的配置】】

Linux下的Petallinux 以及其他的配置 sudo apt-get install iproute2 gawk python3 python build-essential gcc git make net-tools libncurses5-dev tftpd zlib1g-dev libssl-dev flex bison libselinux1 gnupg wget git-core diffstat chrpath socat xterm autoconf libtoo…

可信区块链运行监测服务平台(TBM)发展研讨会在北京召开

2023年11月23日&#xff0c;由中国信息通信研究院、中国移动通信集团设计院有限公司、区块链服务网络&#xff08;BSN&#xff09;发展联盟共同主办的“可信区块链运行监测服务平台&#xff08;TBM&#xff09;发展研讨会”在北京成功举行。会议围绕区块链的监测与治理&#xf…

【全栈开发】Next.js与RedwoodJS——比较js框架

Next.js和RedwoodJS是两个广泛用于构建web应用程序的JavaScript框架。这两个框架都提供了一系列功能和好处&#xff0c;但它们在方法和理念上有所不同。在本文中&#xff0c;我们将仔细研究Next.js和RedwoodJS&#xff0c;并对它们进行比较&#xff0c;以帮助您为项目选择正确的…

Jupyter Notebook本地部署并实现公网远程访问内网Jupyter服务器【内网穿透】

&#x1f525;博客主页&#xff1a; 小羊失眠啦. &#x1f3a5;系列专栏&#xff1a;《C语言》 《数据结构》 《Linux》《Cpolar》 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;…

心智成熟要经过的三个阶段

美国管理学者史蒂芬柯维有一本代表作品《高效能人士的七个习惯》&#xff0c;书中提出了成熟模式图&#xff0c;意思是人需要通过7个习惯&#xff0c;推动心智成熟。 柯维将心智成熟过程分成三个阶段&#xff0c;依赖期、独立期和互赖期。 依赖期是围绕着你&#xff0c;有事情…

C#常见的设计模式-行为型模式

前言 行为型模式是面向对象设计中的一类设计模式&#xff0c;它关注对象之间的通信和相互作用&#xff0c;以实现特定的行为或功能。在C#中&#xff0c;有许多常见的行为型模式&#xff0c;下面将对其中10种行为型模式进行介绍&#xff0c;并给出相应的代码示例。 目录 前言1.…

使用elementPlus去除下拉框蓝色边框

// 下拉框去除蓝色边框 .el-select {--el-select-input-focus-border-color: none !important; }

每日一练2023.11.26——打印沙漏【PTA】

题目要求&#xff1a; 本题要求你写个程序把给定的符号打印成沙漏的形状。例如给定17个“*”&#xff0c;要求按下列格式打印 ************ *****所谓“沙漏形状”&#xff0c;是指每行输出奇数个符号&#xff1b;各行符号中心对齐&#xff1b;相邻两行符号数差2&#xff1b;…

从青铜到王者,小白也能写出高级自动化代码

写代码就像建房子&#xff0c;一砖一瓦大家都知道&#xff0c;难点是在你如何盖的更高级。对于写代码来说&#xff0c;基础语法无非就那几个&#xff0c;很多人都会&#xff0c;关键是如何将代码写得健壮、写得条理清楚。 在学习自动化开发语言过程中&#xff0c;很多人都会有…

ThinkPHP6学生选课管理系统

有需要请加文章底部Q哦 可远程调试 ThinkPHP6学生选课管理系统 一 介绍 此学生选课管理系统基于ThinkPHP6框架开发&#xff0c;数据库mysql8&#xff0c;前端bootstrap。系统角色分为学生&#xff0c;教师和管理员。学生登录后可进行选课&#xff0c;教师登录后可查看选课情况…

「直播预告」替代 Oracle,我们还有多长的路要走?

数字经济浪潮席卷全球&#xff0c;我国数字经济也进入快速发展阶段&#xff0c;作为数字化重要载体&#xff0c;国产软件的重要性不言而喻。近年来&#xff0c;国际局势复杂多变&#xff0c;在客观要求和主观需求的双重驱动下&#xff0c;核心技术自主可控的紧迫性也愈加凸显。…

Gradle更新失败(Error:Connection timed out: connect...)解决方法

一. 发现问题 当我们Copy一个项目或者在不同的机器打开AndroidStudio项目时&#xff0c;可能会遇到这样的问题&#xff1a;Gradle一直在转啊转&#xff0c;然后报错 Error:Connection timed out: connect. If you are behind an HTTP proxy, please configure the proxy setti…

顺序表总结

&#x1f4d1;打牌 &#xff1a; da pai ge的个人主页 &#x1f324;️个人专栏 &#xff1a; da pai ge的博客专栏 ☁️宝剑锋从磨砺出&#xff0c;梅花香自苦寒来 目录 &#x1f324;️arraylist的简…