【C语言】从0到1带你学会文件版动态通讯录
创始人
2024-05-19 18:15:01
0

🌇个人主页:平凡的小苏

📚学习格言:别人可以拷贝我的模式,但不能拷贝我不断往前的激情

🛸C语言专栏:https://blog.csdn.net/vhhhbb/category_12174730.html

小苏希望大家能从这篇文章中收获到许多,如果大家觉得这篇文章对你有帮助,请给小苏点赞+收藏+评论

​ 

目录

 通讯录思维导图

一、Contact.h 

二、Contact.c

1.初始化通讯录

 2.检查容量是否满

 3.添加联系人

4.显示联系人 

 5.查找联系人

6.修改联系人 

 7.通过名字来排序联系人

8.保存联系人到文本文件中 

9.从文件中读取联系人的信息 

10.销毁联系人

 三、text.c


 

 通讯录思维导图

一、Contact.h 

#include
#include
#include
#include
#define NAME_MAX 20
#define SEX_MAX 5
#define TELE_MAX 11
#define ADDR_MAX 30
#define INIT_CAPA 3
#define INC_CAPA 2
typedef struct PeoInfo
{char name[NAME_MAX];int age;char sex[SEX_MAX];char tele[TELE_MAX];char addr[ADDR_MAX];
}PeoInfo;
//动态版本
typedef struct Contact
{PeoInfo* data;int sz;//表示通讯录有多少个联系人int capacity;//表示通讯录的最大容量
}Contact;
//初始化通讯录
void InitContact(Contact* pc);
//添加联系人
void AddContact(Contact* pc);
//删除联系人
void DelContact(Contact* pc);
//显示通讯录
void ShowContact(const Contact* pc);
//查找联系人
void SearchContact(Contact*pc);
//修改联系人’
void ModifyContact(Contact*pc);
//通过名字排序联系人
void ByNameSortContact(Contact* pc);
//销毁联系人
void DestroyContact(Contact* pc);
//保存联系人到文本文件中
void SaveContact(Contact* pc);
//从文件中读取联系人的信息
void GetContact(Contact* pc);

这些是头文件的包含,函数的声明,以及#define定义的常量,为了以后修改方便

二、Contact.c

1.初始化通讯录

void InitContact(Contact* pc)//初始化通讯录
{assert(pc!=NULL);pc-> sz = 0;pc->capacity = INIT_CAPA;PeoInfo * ptr = (PeoInfo*)calloc(INIT_CAPA, sizeof(PeoInfo));if (ptr == NULL){perror("InitContact");return;}pc->data = ptr;GetContact(pc);
}

 初始化通讯录的容量开始为3,sz初始时为0,动态开辟的ptr开辟成功在赋给data。

 2.检查容量是否满

void check_capacity(Contact* pc)//检查容量是否满
{assert(pc);if (pc->capacity == pc->sz){PeoInfo*ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + 2) * sizeof(PeoInfo));if (ptr == NULL){perror("check_capacity");return;}pc->data = ptr;pc->capacity += INC_CAPA;printf("增容成功\n");}
}

如果容量满,则每次增容两个,如果想要增容更多,则修改define定义的常量就可以修改了。

realloc开辟的时候有可能是用pc->data来往后扩大增容,也有可能是用新的空间来开辟,为了防止开辟失败,使原有的数据丢失,则先使用新的指针变量来接收动态开辟的空间,如果开辟成功,再将它赋给data。

 3.添加联系人

void AddContact(Contact* pc)//添加联系人
{assert(pc != NULL);check_capacity(pc);printf("请输入姓名:\n");scanf("%s", pc->data[pc->sz].name);printf("请输入年龄:\n");scanf("%d", &(pc->data[pc->sz].age));printf("请输入性别:\n");scanf("%s", pc->data[pc->sz].sex);printf("请输入号码:\n");scanf("%s", pc->data[pc->sz].tele);printf("请输入地址:\n");scanf("%s", pc->data[pc->sz].addr);printf("添加联系人成功\n");pc->sz++;
}

添加联系人前,需要先判断是否需要增容

4.显示联系人 

void ShowContact(const Contact* pc)//显示联系人
{assert(pc != NULL);printf("%-20s\t%-4s\t%-4s\t%-12s\t%-30s\n","姓名","年龄","性别","电话号码","地址");for (int i = 0; i < pc->sz; i++){printf("%-20s\t%-4d\t%-4s\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);}
}

 5.查找联系人

int ByNameFind(Contact* pc, char name[])//通过名字查找联系人
{for (int i = 0; i < pc->sz; i++){if (strcmp(pc->data[i].name, name) == 0){return i;}}return -1;
}
void SearchContact(Contact* pc)//查找联系人
{assert(pc);char name[NAME_MAX];printf("请输入要查找的联系人\n");scanf("%s", name);int ret = ByNameFind(pc, name);if (ret == -1){printf("查无此人\n");return;}printf("%-20s\t%-4s\t%-4s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话号码", "地址");printf("%-20s\t%-4d\t%-4s\t%-12s\t%-30s\n", pc->data[ret].name,pc->data[ret].age,pc->data[ret].sex,pc->data[ret].tele,pc->data[ret].addr);
}

注意:名字属于字符串,名字的比较需要用strcmp来比较,如果返回-1,则是没有找到联系人,如果找到了,则就打印这个联系人的信息出来

6.修改联系人 

void ModifyContact(Contact* pc)//修改联系人
{assert(pc);char name[NAME_MAX];printf("请输入要修改的联系人姓名\n");scanf("%s", name);int pos = ByNameFind(pc, name);if (pos == -1){printf("找不到该联系人\n");return;}printf("请输入姓名:\n");scanf("%s", pc->data[pos].name);printf("请输入年龄:\n");scanf("%d", &(pc->data[pos].age));printf("请输入性别:\n");scanf("%s", pc->data[pos].sex);printf("请输入号码:\n");scanf("%s", pc->data[pos].tele);printf("请输入地址:\n");scanf("%s", pc->data[pos].addr);printf("修改联系人成功\n");
}

注意:想要修改这个联系人,也需要通讯录中有这个联系人,所以要先查找到这个联系人,所以调用封装好的通过名字查找联系人这个函数就可以了,如果返回-1,则就是没有该联系人,无法修改,如果找到了,则才能够修改此联系人的信息。

 7.通过名字来排序联系人

void ByNameSortContact(Contact* pc)//通过名字来排序
{assert(pc);if (pc->sz == 0){printf("无联系人,无法排序\n");return;}PeoInfo temp;for (int i = 0; i < pc->sz - 1; i++){for(int j = 0 ;jsz-1-i;j++){if (strcmp(pc->data[j].name, pc->data[j + 1].name) > 0){temp = pc->data[j];pc->data[j] = pc->data[j + 1];pc->data[j + 1] = temp;}}}printf("排序成功\n");
}

注意:这里通过名字来排序联系人,也是需要用到strcmp这个库函数的,strcmp是一个字符来比较的,如果有一个字符大的话就要进行交换,利用的是冒泡排序思想来排序联系人的

8.保存联系人到文本文件中 

void SaveContact(Contact* pc)
{assert(pc);FILE* pf = fopen("Contact.txt", "wb");if (pf == NULL){perror("fopen");}else{for (int i = 0; i < pc->sz; i++){fwrite(pc->data + i, sizeof(PeoInfo), 1, pf);}fclose(pf);pf = NULL;printf("保存数据成功\n");}
}

注意:FILE是C语言标准的指针,wb是用二进制的方式写入文本文件中,而fwrite的用法我们可以利用cplusplus来查找它的用法,里面介绍了它的每个参数的用法,第一个参数ptr其实就是传我们的data的指针进去,第二个参数本质就是求大小的,求得是PeoInfo得大小,第三个参数就是每次添加几个联系人,每次添加1个。第四个参数是把文件流放入

9.从文件中读取联系人的信息 

//从文件中初始化联系人
void GetContact(Contact* pc)
{assert(pc);FILE* pf = fopen("Contact.txt", "rb");if (pf == NULL){perror("GetContact::fopen");}else{PeoInfo ptr = { 0 };int i = 0;while (fread(&ptr, sizeof(PeoInfo), 1, pf)){check_capacity(pc);pc->data[i] = ptr;i++;pc->sz++;}fclose(pf);pf = NULL;}
}

注意:rb是利用二进制来读取联系人的,fread的用法如上图所示。

10.销毁联系人

//销毁联系人
void DestroyContact(Contact* pc)
{free(pc->data);pc->data = NULL;pc->capacity = 0;pc->sz = 0;
}

注意:在我们退出通讯录时,要将它进行销毁 

 三、text.c

#include"Contact.h"
void menu()
{printf("**********************************\n");printf("*******1.Add      2.Del   ********\n");printf("*******3.Search   4.Modify********\n");printf("*******5.Show     6.Sort  ********\n");printf("*******0.exit             ********\n");printf("**********************************\n");
}
enum Option
{EXIT,ADD,DEL,SEARCH,MODIFY,SHOW,SORT};
int main()
{Contact con;InitContact(&con);int input = 0;do{menu();printf("请输入数字:\n");scanf("%d", &input);switch (input){case ADD:AddContact(&con);break;case DEL :DelContact(&con);break;case SEARCH:SearchContact(&con);break;case MODIFY:ModifyContact(&con);break;case SHOW:ShowContact(&con);break;case SORT:ByNameSortContact(&con);break;case EXIT:SaveContact(&con);DestroyContact(&con);printf("退出程序\n");break;default:printf("输入错误,请重新输入\n");break;}} while (input);return 0;

注意:首先要建立菜单,然后用枚举来定义case后面,这样为了可以让我们看代码更清晰,在运行程序时要将联系人从文件中读取出来,在退出文件时,要把联系人保存到文本文件中去,在进行销毁。

 好了,小编的分享到这里就结束了,如果有什么不足的地方请大佬多多指教!!!

相关内容

热门资讯

常用商务英语口语   商务英语是以适应职场生活的语言要求为目的,内容涉及到商务活动的方方面面。下面是小编收集的常用商务...
六年级上册英语第一单元练习题   一、根据要求写单词。  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 ...