【c语言进阶】动态通讯录
创始人
2024-05-22 00:35:07
0

在这里插入图片描述

🚀write in front🚀
📜所属专栏: c语言学习
🛰️博客主页:睿睿的博客主页
🛰️代码仓库:🎉VS2022_C语言仓库
🎡您的点赞、关注、收藏、评论,是对我最大的激励和支持!!!
关注我,关注我,关注我你们将会看到更多的优质内容!!

在这里插入图片描述

文章目录

  • 前言:
  • 一、静态通讯录的弊端:
  • 二、动态增容优化通讯录:
    • 2.1.枚举类型的加入
    • 2.2.结构体的修改
    • 2.3.Initcontact函数的修改
    • 2.4.Addcontact函数的修改
    • 2.5.Desdrycontact函数的添加
  • 三、文件操作优化通讯录:
    • 3.1.Savecontact函数的添加(通讯录信息保存)
    • 3.2.Loadcontact函数的添加(导入通讯录信息)
  • 四、完整代码展示:
    • contact.h:
    • test.c
    • contact.c
  • 总结:

前言:

  在前面的学习中,我们写了静态通讯录:c语言实现静态通讯录

一、静态通讯录的弊端:

  对于简易版本的通讯录来说,我们是直接指定了通讯录的大小,那么此时我们会发现两个弊端:

弊端1:

  如果我们创建的通讯录空间过大,就会浪费空间;如果我们创建的通讯录太小又不够使用 。所以,此时我们就得优化通信录给定空间上的问题,不能再给其指定大小的空间,而是让其空间有灵活性此时我们以动态增容的方式来给定通讯录的空间,就很好的规避了这一问题!

弊端2:

  我们知道程序运行起来我们输入的数据都是保存在内存上的,在简易版本中我们在运行通讯录之后添加的数据,在程序结束的时候都会被清除。当而我们既然要保存联系人的信息,就得做到数据持久化的保存,我们就得将数据保存到硬盘中,也就是文件当中,此时我们可以用文件操作的方式来实现持久化的保存联系人信息。

二、动态增容优化通讯录:

2.1.枚举类型的加入

  在前面我们学习了枚举类型的使用,我们在写menu菜单的switch函数时,常常会因为不知道数字对应的是哪一个功能而弄混。
  枚举类型中各成员的从零开始依次递增,于是我们可以再使用一个枚举类型来使我们的选项对应用户的选择:

enum OPTION
{Exit = 0,Add = 1,Del,Search,Modify,Print,sort
};

  这样一来,我们就可以把case后面的1,2,3等数据换成对应的功能名字。
case 1:替换为case Add:

2.2.结构体的修改

  之前我们创建了两个结构体,第一个存放信息,第二个存放信息的数组和联系人数量,可是第二个存放的人信息的数组规定死了100个元素。所以我们将第二个结构体做一下改动即可:

//静态版本
//typedef struct contact
//{
//	PeoInfo data[MAX];
//	int sz;
//}contact;//动态版本
typedef struct Contact
{PeoInfo* data;//指向存放人的信息的空间int sz;//当前已经放的信息的个数int capacity;//当前通讯录的最大容量
}contact;

  这里我们用sz记录联系人数量,用capacity指向当前通讯录的最大容量。在这里我们会发现结构体明显小了很多,因为存放人信息的空间我们还没有创建!

2.3.Initcontact函数的修改

  之前的初始化仅仅只是将所有的数据初始化为0,但是动态版本的通讯录还没有开辟联系人的空间。所有我们要在初始化函数里完成这个操作。

//静态版本:
//void Initcontact(contact* con)
//{
//	assert(con);
//	con->sz = 0;
//	memset(con->data, 0, sizeof(con->data));
//}//动态版本:
void Initcontact(contact* con)
{assert(con);//DEFAULT_SZ是宏定义的3,在contact.h有添加!PeoInfo *ptr= (PeoInfo*)calloc(DEFAULT_SZ, sizeof(PeoInfo));if (ptr == NULL){perror("InitContact::calloc");return;}con->sz = 0;con->capacity = DEFAULT_SZ;con->data = ptr;//这里的Loadcontact函数在下面会提到!LoadContact(con);
}

  在这里大家就不用自己初始化联系人信息了!因为calloc本身就有这个功能!

2.4.Addcontact函数的修改

  之前静态通讯录的添加联系人只需要在不超过容量的基础上添加即可,超过容量就不能操作了。但是动态通讯录在发现容量不足时要有自动增容的功能,这也是动态通讯录的有点所在!

//静态add
//void AddContact(contact* con)
//{
//	assert(con);
//	if (con->sz == 99)
//	{
//		printf("通讯录已经存满,请联系操作人员");
//		return;
//	}
//	printf("请输入联系人姓名:>");
//	scanf("%s", con->data[con->sz].name);
//	printf("请输入联系人性别:>");
//	scanf("%s",con->data[con->sz].sex);
//	printf("请输入联系人年龄:>");
//	scanf("%d", &(con->data[con->sz].age));
//	printf("请输入联系人联系方式:>");
//	scanf("%s", con->data[con->sz].tele);
//	printf("请输入联系人住址:>");
//	scanf("%s", con->data[con->sz].addr);
//	printf("联系人信息添加成功!\n");
//	con->sz++;
//}
// 
//判断容量是否够用!并且自动增容
void check_capacity(contact* con)
{assert(con);if (con->sz == con->capacity){printf("内存已满,正在扩容——\n");Sleep(1000);PeoInfo* ptr = (PeoInfo*)realloc(con->data, (con->capacity + INC_SZ) * sizeof(PeoInfo));if (ptr==NULL){perror("check_capacity::realloc");return;}con->capacity += INC_SZ;con->data = ptr;printf("扩容成功\n");}
}
//动态add
void AddContact(contact* con)
{assert(con);check_capacity(con);printf("请输入联系人姓名:>");scanf("%s", con->data[con->sz].name);printf("请输入联系人性别:>");scanf("%s", con->data[con->sz].sex);printf("请输入联系人年龄:>");scanf("%d", &(con->data[con->sz].age));printf("请输入联系人联系方式:>");scanf("%s", con->data[con->sz].tele);printf("请输入联系人住址:>");scanf("%s", con->data[con->sz].addr);printf("联系人信息添加成功!\n");con->sz++;
}

2.5.Desdrycontact函数的添加

  在使用完堆区的空间之后,最重要的事情是什么?当然是释放这块空间呀!

void DestroyContact(contact* con)
{free(con->data);con->data = NULL;con->sz = 0;con->capacity = 0;con = NULL;
}

三、文件操作优化通讯录:

3.1.Savecontact函数的添加(通讯录信息保存)

  为了在保存内存中操作完成后的所有联系人信息,我们在程序退出之前将联系人信息以2进制的方式写进文件里面

void SaveContact(contact* con)
{FILE* fp = fopen("contact.txt", "wb");if (fp==NULL){perror("SaveContact");}else{ printf("正在保存\n");Sleep(1000);for (int i = 0; i < con->sz; i++)fwrite(con->data + i, sizeof(PeoInfo), 1, fp);fclose(fp);fp = NULL;printf("保存成功\n");}
}

3.2.Loadcontact函数的添加(导入通讯录信息)

  在我们对于通讯录进行修改时,要将之前文件中存好的信息导入内存中去,这个步骤也应该在初始化函数中进行,我们将他分装为函数,代码如下:

void LoadContact(contact* con)
{FILE* fp = fopen("contact.txt", "rb");PeoInfo str={ 0 };if (fp==NULL){perror("LoadContact");}else{printf("正在加载>>>\n");Sleep(1000);int i = 0;while (fread(&str, sizeof(PeoInfo), 1, fp)){check_capacity(con);con->data[i] = str;con->sz++;i++;}}fclose(fp);fp = NULL;printf("加载成功!\n");
}

四、完整代码展示:

contact.h:


#pragma once
#include
#include
#include
#include#define MAX 100
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 12
#define MAX_ADDR 20#define DEFAULT_SZ 3
#define INC_SZ 2enum OPTION
{Exit = 0,Add = 1,Del,Search,Modify,Print,sort
};typedef struct PeoInfo
{char name[MAX_NAME];char sex[MAX_SEX];int age;char addr[MAX_ADDR];char tele[MAX_TELE];
}PeoInfo;//静态版本
//typedef struct contact
//{
//	PeoInfo data[MAX];
//	int sz;
//}contact;//动态版本
typedef struct Contact
{PeoInfo* data;//指向存放人的信息的空间int sz;//当前已经放的信息的个数int capacity;//当前通讯录的最大容量
}contact;//初始化消息
void Initcontact(contact *con);//增加消息
void AddContact(contact *con);//删除信息
void DelContact(contact *con);//查找个别人消息
void SeachContact(contact *con);//修改个别人消息
void ModifyContact(contact* con);//打印全部通讯录
void PrintContact(contact* con);//排序通讯录
void sortContact(contact* con);//保存通讯录中的信息到文件中
void SaveContact(contact* con);//加载文件信息到通讯录
void LoadContact(contact* con);

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"void menu()
{printf("**********************************\n");printf("**********************************\n");printf("******** 欢迎使用本通讯录 ********\n");printf("**********************************\n");printf("***** 本通讯录现提供以下功能 *****\n");printf("************ 1.Add ***************\n");printf("************ 2.Del ***************\n");printf("************ 3.Search ************\n");printf("************ 4.Modify ************\n");printf("************ 5.Print *************\n");printf("************ 6.sort **************\n");printf("************ 0.exit**************\n");printf("**********************************\n");
}
void Contact()
{int input = 0;contact con;Initcontact(&con);do{menu();printf("请选择>");scanf("%d", &input);switch (input){case Add:AddContact(&con);break;case Del:DelContact(&con);break;case Search:SeachContact(&con);break;case Modify:ModifyContact(&con);break;case Print:PrintContact(&con);break;case sort:sortContact(&con);break;case Exit:SaveContact(&con);DestroyContact(&con);printf("已成功退出");break;default:printf("输入错误,请重新输入\n");break;}} while (input);}
int main()
{Contact();return 0;
}

contact.c

#define _CRT_SECURE_NO_WARNINGS 1#include "contact.h"int FindByName(contact* con, char name[])
{assert(con);int i = 0;for (i = 0; i < con->sz; i++){if (strcmp(con->data[i].name,name) == 0){return i;}}return -1;
}
//静态版本:
//void Initcontact(contact* con)
//{
//	assert(con);
//	con->sz = 0;
//	memset(con->data, 0, sizeof(con->data));
//}//动态版本:
void Initcontact(contact* con)
{assert(con);PeoInfo *ptr= (PeoInfo*)calloc(DEFAULT_SZ, sizeof(PeoInfo));if (ptr == NULL){perror("InitContact::calloc");return;}con->sz = 0;con->capacity = DEFAULT_SZ;con->data = ptr;LoadContact(con);
}void DestroyContact(contact* con)
{free(con->data);con->data = NULL;con->sz = 0;con->capacity = 0;con = NULL;//??}
//静态add
//void AddContact(contact* con)
//{
//	assert(con);
//	if (con->sz == 99)
//	{
//		printf("通讯录已经存满,请联系操作人员");
//		return;
//	}
//	printf("请输入联系人姓名:>");
//	scanf("%s", con->data[con->sz].name);
//	printf("请输入联系人性别:>");
//	scanf("%s",con->data[con->sz].sex);
//	printf("请输入联系人年龄:>");
//	scanf("%d", &(con->data[con->sz].age));
//	printf("请输入联系人联系方式:>");
//	scanf("%s", con->data[con->sz].tele);
//	printf("请输入联系人住址:>");
//	scanf("%s", con->data[con->sz].addr);
//	printf("联系人信息添加成功!\n");
//	con->sz++;
//}
// void check_capacity(contact* con)
{assert(con);if (con->sz == con->capacity){printf("内存已满,正在扩容——\n");Sleep(1000);PeoInfo* ptr = (PeoInfo*)realloc(con->data, (con->capacity + INC_SZ) * sizeof(PeoInfo));if (ptr==NULL){perror("check_capacity::realloc");return;}con->capacity += INC_SZ;con->data = ptr;printf("扩容成功\n");}
}
//动态add
void AddContact(contact* con)
{assert(con);check_capacity(con);printf("请输入联系人姓名:>");scanf("%s", con->data[con->sz].name);printf("请输入联系人性别:>");scanf("%s", con->data[con->sz].sex);printf("请输入联系人年龄:>");scanf("%d", &(con->data[con->sz].age));printf("请输入联系人联系方式:>");scanf("%s", con->data[con->sz].tele);printf("请输入联系人住址:>");scanf("%s", con->data[con->sz].addr);printf("联系人信息添加成功!\n");con->sz++;
}
void DelContact(contact* con)
{assert(con);char name[100];if (con->sz == 0){printf("通讯录为空,无法删除\n");return;}printf("请输入要删除人名字:>");scanf("%s", name);int ret = FindByName(con, name);int i = 0;if (-1 == ret){printf("没有找到此人\n");return;}else{for (i = ret; i < con->sz-1; i++){con->data[i] = con->data[i + 1];}con->sz--;memset(&con->data[i], 0, sizeof(con->data[i]));printf("删除成功!\n");}
}void SeachContact(contact* con)
{assert(con);char name[MAX_NAME];if (con->sz == 0){printf("通讯录为空,无法输入\n");return;}printf("请输入查找人名字");scanf("%s", name);int ret = FindByName(con, name);if (ret == -1){printf("您查找的人不存在!\n");return;}printf("%-20s\t%-4s\t%-5s\t%-20s\t%-12s\n", "姓名", "年龄", "性别", "地址", "电话");printf("%-20s\t%-4d\t%-5s\t%-20s\t%-12s\n", con->data[ret].name, con->data[ret].age, con->data[ret].sex, con->data[ret].addr, con->data[ret].tele);
}void ModifyContact(contact* con)
{assert(con);char name[MAX_NAME] = { 0 };if (con->sz == 0){printf("通讯录为空,无法修改\n");return;}printf("请输入查找人名字");scanf("%s", name);int ret = FindByName(con, name);if (-1 == ret){printf("您要修改的人不存在\n");return;}printf("请输入联系人姓名:>");scanf("%s", con->data[ret].name);printf("请输入联系人性别:>");scanf("%s", con->data[ret].sex);printf("请输入联系人年龄:>");scanf("%d", &(con->data[ret].age));printf("请输入联系人住址:>");scanf("%s", con->data[ret].addr);printf("请输入联系人联系方式:>");scanf("%s", con->data[ret].tele);printf("联系人信息修改成功!\n");
}void PrintContact(contact* con)
{printf("%-10s\t%-20s\t%-4s\t%-5s\t%-20s\t%-12s\n","联系人", "姓名", "年龄", "性别", "地址", "电话");for (int i = 0; i < con->sz; i++){printf("%-10d\t%-20s\t%-4d\t%-5s\t%-20s\t%-12s\n",i+1, con->data[i].name,con->data[i].age,con->data[i].sex,con->data[i].addr,con->data[i].tele);}
}int cmp_con_by_name(const void* e1, const void* e2)
{return (strcmp(((PeoInfo *)e1)->name, ((PeoInfo*)e2)->name));
}
void sortContact(contact* con)
{assert(con);if (0 == con->sz){printf("通讯录为空,无法排序\n");return;}qsort(con->data, con->sz, sizeof(con->data[0]), cmp_con_by_name);printf("排序成功\n");
}void SaveContact(contact* con)
{FILE* fp = fopen("contact.txt", "wb");if (fp==NULL){perror("SaveContact");}else{ printf("正在保持\n");Sleep(1000);for (int i = 0; i < con->sz; i++)fwrite(con->data + i, sizeof(PeoInfo), 1, fp);fclose(fp);fp = NULL;printf("保存成功\n");}
}void LoadContact(contact* con)
{FILE* fp = fopen("contact.txt", "rb");PeoInfo str={ 0 };if (fp==NULL){perror("LoadContact");}else{printf("正在加载>>>\n");Sleep(1000);int i = 0;while (fread(&str, sizeof(PeoInfo), 1, fp)){check_capacity(con);con->data[i] = str;con->sz++;i++;}}fclose(fp);fp = NULL;printf("加载成功!\n");
}

总结:

  我们通过文件操作的知识和动态内存空间管理的知识终于完善了动态通讯录的编写!相信大家在自己真正写出来之后都会感觉学有所成!
  更新不易,辛苦各位小伙伴们动动小手,👍三连走一走💕💕 ~ ~ ~ 你们真的对我很重要!最后,本文仍有许多不足之处,欢迎各位认真读完文章的小伙伴们随时私信交流、批评指正!

专栏订阅:
每日一题
c语言学习
算法
智力题
更新不易,辛苦各位小伙伴们动动小手,👍三连走一走💕💕 ~ ~ ~ 你们真的对我很重要!最后,本文仍有许多不足之处,欢迎各位认真读完文章的小伙伴们随时私信交流、批评指正!

在这里插入图片描述

相关内容

热门资讯

常用商务英语口语   商务英语是以适应职场生活的语言要求为目的,内容涉及到商务活动的方方面面。下面是小编收集的常用商务...
六年级上册英语第一单元练习题   一、根据要求写单词。  1.dry(反义词)__________________  2.writ...
复活节英文怎么说 复活节英文怎么说?复活节的英语翻译是什么?复活节:Easter;"Easter,anniversar...
2008年北京奥运会主题曲 2008年北京奥运会(第29届夏季奥林匹克运动会),2008年8月8日到2008年8月24日在中华人...
英语道歉信 英语道歉信15篇  在日常生活中,道歉信的使用频率越来越高,通过道歉信,我们可以更好地解释事情发生的...
六年级英语专题训练(连词成句... 六年级英语专题训练(连词成句30题)  1. have,playhouse,many,I,toy,i...
上班迟到情况说明英语   每个人都或多或少的迟到过那么几次,因为各种原因,可能生病,可能因为交通堵车,可能是因为天气冷,有...
小学英语教学论文 小学英语教学论文范文  引导语:英语教育一直都是每个家长所器重的,那么有关小学英语教学论文要怎么写呢...
英语口语学习必看的方法技巧 英语口语学习必看的方法技巧如何才能说流利的英语? 说外语时,我们主要应做到四件事:理解、回答、提问、...
四级英语作文选:Birth ... 四级英语作文范文选:Birth controlSince the Chinese Governmen...
金融专业英语面试自我介绍 金融专业英语面试自我介绍3篇  金融专业的学生面试时,面试官要求用英语做自我介绍该怎么说。下面是小编...
我的李老师走了四年级英语日记... 我的李老师走了四年级英语日记带翻译  我上了五个学期的小学却换了六任老师,李老师是带我们班最长的语文...
小学三年级英语日记带翻译捡玉... 小学三年级英语日记带翻译捡玉米  今天,我和妈妈去外婆家,外婆家有刚剥的`玉米棒上带有玉米籽,好大的...
七年级英语优秀教学设计 七年级英语优秀教学设计  作为一位兢兢业业的人民教师,常常要写一份优秀的教学设计,教学设计是把教学原...
我的英语老师作文 我的英语老师作文(通用21篇)  在日常生活或是工作学习中,大家都有写作文的经历,对作文很是熟悉吧,...
英语老师教学经验总结 英语老师教学经验总结(通用19篇)  总结是指社会团体、企业单位和个人对某一阶段的学习、工作或其完成...
初一英语暑假作业答案 初一英语暑假作业答案  英语练习一(基础训练)第一题1.D2.H3.E4.F5.I6.A7.J8.C...
大学生的英语演讲稿 大学生的英语演讲稿范文(精选10篇)  使用正确的写作思路书写演讲稿会更加事半功倍。在现实社会中,越...
VOA美国之音英语学习网址 VOA美国之音英语学习推荐网址 美国之音网站已经成为语言学习最重要的资源站点,在互联网上还有若干网站...
商务英语期末试卷 Part I Term Translation (20%)Section A: Translate ...