【C】—文件版本通讯录的实现
创始人
2024-04-10 06:43:52
0

关于C语言的知识放在专栏:C
小菜坤日常上传gitee代码:https://gitee.com/qi-dunyan
❤❤❤
个人简介:双一流非科班的一名小白,期待与各位大佬一起努力!
在这里插入图片描述

目录

  • 思路
  • 代码实现
  • 完整代码(可自取)

思路

在前面的文章中,已经讲解了动态版本的通讯录的实现,但是动态通讯录存在一个致命缺陷,就是它不能自动保存数据,而前面一篇文章中学到了数据持久化的方法之一:即把数据存放在磁盘文件上,便可以实现数据持久化。
具体应该如何做呢?
假如我们在退出的时候,通过文件操作,把我们所写的数据存在磁盘文件里,然后我们再进行下一次的使用的时候,在初始化阶段就从磁盘中读取这些数据,这不就实现了。

代码实现

代码的实现并不困难,只不过是在动态内存版本的基础上进行了一些文件操作,用来保存和读取数据。
从文件中读取信息(初始化阶段完成)

//读通讯录文件信息
//size_t fread(void* ptr, size_t size, size_t count, FILE* stream)
void Load_Contact(struct contact* p)
{//二进制读FILE* pfR = fopen("通讯录.txt", "rb");if (pfR == NULL){//读取失败打印错误报告perror("Load_Contact::fopen");return;}struct message pf = { 0 };//fread返回值为读取的完整的元素个数,这里读取成功返回1,失败0while (fread(&pf, sizeof(pf), 1, pfR)){//判断是否增容check_capacity(p);p->data[p->sz] = pf;p->sz++;}//关闭文件fclose(pfR);pfR = NULL;
}//初始化通讯录
void Init_contact(struct contact* p)
{assert(p);//开辟空间p->data =(struct message*) malloc(DEFAULT_SZ * sizeof(struct message));//假如开辟失败,报错if (p->data == NULL){printf("%s\n", strerror(errno));return;}p->sz = 0;p->capacity = DEFAULT_SZ;//加载通讯录信息Load_Contact(p);
}

这里在动态版本的基础上,在初始化阶段加入了一个Load_Contact()函数,这个是用来以二进制读的方式打开文件,并且把读取到的信息放在结构体pf里,然后再将pf赋值到p指向的data数组的下标为size空间。
在这里插入图片描述
将数据写入文件(退出时保存信息)
在这里插入图片描述
这一步是为了将我们本次所写的数据,写入到文件中去,以备下一次打开时好从中读取数据。具体代码如下:

//写数据(保存通讯录信息)
//size_t fwrite(const void* ptr, size_t size, size_t count, FILE* stream)
void Storage_Contact(struct contact* p)
{//二进制形式写FILE* pfW = fopen("通讯录.txt", "wb");if (pfW == NULL){//失败则打印错误报告perror("Storage_Contact::fopen");return;}int i = 0;//将sz个数据都写入到文件中for (i = 0; i < p->sz; i++){fwrite(p->data + i, sizeof(struct message), 1, pfW);}//关闭fclose(pfW);pfW = NULL;
}

正是有了这一步,我们在退出时会创建一个文件来保存信息。供下一次读取。如以下视频所示:在我第二次运行程序时,上一次的数据已经加载完毕了。实现了数据持久化。

文件版本通讯录(退出可保存信息)

完整代码(可自取)

.h头文件

#pragma once
#include
#include
#include
#include
#include
#include#define NAME 20
#define SEX 5
#define TELE 12
#define ADDR 30#define DEFAULT_SZ 3//初始容量
#define INC_SZ 2//扩容//联系人信息
struct message
{//姓名char name[NAME];//性别char sex[SEX];//电话char tele[TELE];//住址char addr[ADDR];//年龄int age;
};
//通讯录
struct contact
{struct message* data;int sz;//个数int capacity;//通讯录容量
};
//初始化通讯录
void Init_contact(struct contact* p);
//动态增加联系人
void Add_contact(struct contact* p);
//显示联系人
void Show_contact(const struct contact* p);
//删除联系人
void Dele_contact(struct contact* p);
//修改联系人信息
void revise_contact(struct contact* p);
//查找联系人信息
void Find_contact(const struct contact* p);
//排序联系人
void Sort_contact(struct contact* p);
//清空联系人
void Clean(struct contact* p);
//释放空间
void Destory_contact(struct contact* p);
//保存数据
void Storage_Contact(struct contact* p);

.c源文件(函数定义)

#include"Contact_exe.h"//是否判断增容
int check_capacity(struct contact* p)
{//当联系人个数 == 通讯录容量时,增容INC_SZ个内存空间if (p->sz == p->capacity){struct message* ptr = (struct message*)realloc(p->data, (p->capacity + INC_SZ) * sizeof(struct message));if (ptr == NULL)//判断是否增容失败{printf("%s\n", strerror(errno));return 0;}else{p->data = ptr;//增容成功,data就指向这块新开辟的空间p->capacity += INC_SZ;//容量+=INC_SZ//printf("增容成功!\n");return 1;}}//不需要增容elsereturn 1;
}//读通讯录文件信息
//size_t fread(void* ptr, size_t size, size_t count, FILE* stream)
void Load_Contact(struct contact* p)
{//二进制读FILE* pfR = fopen("通讯录.txt", "rb");if (pfR == NULL){//读取失败打印错误报告perror("Load_Contact::fopen");return;}struct message pf = { 0 };//fread返回值为读取的完整的元素个数,这里读取成功返回1,失败0while (fread(&pf, sizeof(pf), 1, pfR)){//判断是否增容check_capacity(p);p->data[p->sz] = pf;p->sz++;}//关闭文件fclose(pfR);pfR = NULL;
}//初始化通讯录
void Init_contact(struct contact* p)
{assert(p);//开辟空间p->data =(struct message*) malloc(DEFAULT_SZ * sizeof(struct message));//假如开辟失败,报错if (p->data == NULL){printf("%s\n", strerror(errno));return;}p->sz = 0;p->capacity = DEFAULT_SZ;//加载通讯录信息Load_Contact(p);
}//增加联系人
void Add_contact(struct contact* p)
{assert(p);if (0 == check_capacity(p)){printf("%s\n", strerror(errno));return;}printf("请输入姓名:->");scanf("%s", p->data[p->sz].name);printf("请输入性别:->");scanf("%s", p->data[p->sz].sex);printf("请输入电话:->");scanf("%s", p->data[p->sz].tele);printf("请输入住址:->");scanf("%s", p->data[p->sz].addr);printf("请输入年龄:->");scanf("%d", &(p->data[p->sz].age));system("cls");printf("增加成功!\n");printf("\n");p->sz++;
}
//显示联系人
void Show_contact(const struct contact* p)
{assert(p);int i = 0;printf("%-20s\t%-5s\t%-12s\t%-20s\t%-5s\n", "姓名", "性别", "电话", "住址", "年龄");for (i = 0; i < p->sz; i++){printf("%-20s\t%-5s\t%-12s\t%-20s\t%-5d\n", p->data[i].name,p->data[i].sex,p->data[i].tele,p->data[i].addr,p->data[i].age);}
}
int find_name(const struct contact* p, char arr[])
{assert(p);int i = 0;for (i = 0; i < p->sz; i++){if (0 == strcmp(p->data[i].name, arr))return i;}return -1;
}
//删除联系人
void Dele_contact(struct contact* p)
{assert(p);char del_name[NAME];printf("请输入要删除联系人的姓名:->");scanf("%s", del_name);//查找该联系人int ret = find_name(p, del_name);if (ret == -1)printf("查无此人!\n");else{int j = 0;for (j = ret; j < p->sz - 1; j++){p->data[j] = p->data[j + 1];}p->sz--;system("cls");printf("删除成功!\n");printf("\n");}
}
//修改菜单栏
void menu_()
{printf("***********************************\n");printf("******   1、修改联系人姓名   ******\n");printf("******   2、修改联系人电话   ******\n");printf("******   3、修改联系人年龄   ******\n");printf("******   4、修改联系人住址   ******\n");printf("******   5、修改联系人性别   ******\n");printf("******   0、返回主菜单       ******\n");}
//修改联系人信息
void revise_contact(struct contact* p)
{assert(p);char del_name[NAME];printf("请输入要修改信息的联系人的姓名:->");scanf("%s", del_name);int ret = find_name(p, del_name);if (ret == -1){printf("查无此人!\n");printf("\n");}else{int in_put = 0;do{menu_();scanf("%d", &in_put);switch (in_put){case 1:printf("请输入修改后的姓名:->");scanf("%s", p->data[ret].name);system("cls");printf("姓名修改成功!\n");break;case 2:printf("请输入修改后的电话:->");scanf("%s", p->data[ret].tele);system("cls");printf("电话修改成功!\n");break;case 3:printf("请输入修改后的年龄:->");scanf("%d", &(p->data[ret].age));system("cls");printf("年龄修改成功!\n");break;case 4:printf("请输入修改后的住址:->");scanf("%s", p->data[ret].addr);system("cls");printf("住址修改成功!\n");break;case 5:printf("请输入修改后的性别:->");scanf("%s", p->data[ret].sex);system("cls");printf("性别修改成功!\n");break;case 0:printf("取消修改!\n");break;default:printf("输入错误!\n");break;}} while (in_put);}
}
//查找联系人信息
void Find_contact(const struct contact* p)
{assert(p);char del_name[NAME];printf("请输入要查找联系人的姓名:->");scanf("%s", del_name);system("cls");//查找该联系人int ret = find_name(p, del_name);if (ret == -1)printf("查无此人!\n");else{printf("%-20s\t%-5s\t%-12s\t%-20s\t%-5s\n", "姓名", "性别", "电话", "住址", "年龄");printf("%-20s\t%-5s\t%-12s\t%-20s\t%-5d\n", p->data[ret].name,p->data[ret].sex,p->data[ret].tele,p->data[ret].addr,p->data[ret].age);}
}
//排序菜单
void menu_sort()
{printf("******   1、姓名   ******\n");printf("******   2、住址   ******\n");printf("******   3、年龄   ******\n");printf("******   4、性别   ******\n");printf("******   0、退出   ******\n");
}//姓名排序
int cmp_name(const void* e1, const void* e2)
{return strcmp(((struct message*)e1)->name, ((struct message*)e2)->name);
}
//住址排序
int cmp_addr(const void* e1, const void* e2)
{return strcmp(((struct message*)e1)->addr, ((struct message*)e2)->addr);
}
//年龄排序
int cmp_age(const void* e1, const void* e2)
{return ((struct message*)e1)->age - ((struct message*)e2)->age;
}
//性别排序
int cmp_sex(const void* e1, const void* e2)
{return strcmp(((struct message*)e1)->sex, ((struct message*)e2)->sex);
}
//排序联系人
void Sort_contact(struct contact* p)
{int s = 0;do{//排序菜单menu_sort();printf("请选择排序类型:->");scanf("%d", &s);system("cls");switch (s){case 1:qsort(p->data, p->sz, sizeof(struct message), cmp_name);printf("排序成功!\n");break;case 2:qsort(p->data, p->sz, sizeof(struct message), cmp_addr);printf("排序成功!\n");break;case 3:qsort(p->data, p->sz, sizeof(struct message), cmp_age);printf("排序成功!\n");break;case 4:qsort(p->data, p->sz, sizeof(struct message), cmp_sex);printf("排序成功!\n");break;case 0:printf("退出排序\n");break;default:printf("输入有误!\n");break;}} while (s);
}//清空联系人
void Clean(struct contact* p)
{p->sz = 0;printf("清空成功!\n");
}//释放空间
void Destory_contact(struct contact* p)
{free(p->data);p->data=NULL;p->sz = 0;p->capacity = 0;
}
//写数据(保存通讯录信息)
//size_t fwrite(const void* ptr, size_t size, size_t count, FILE* stream)
void Storage_Contact(struct contact* p)
{//二进制形式写FILE* pfW = fopen("通讯录.txt", "wb");if (pfW == NULL){//失败则打印错误报告perror("Storage_Contact::fopen");return;}int i = 0;for (i = 0; i < p->sz; i++){fwrite(p->data + i, sizeof(struct message), 1, pfW);}fclose(pfW);pfW = NULL;
}

.c源文件(测试)

#include"Contact_exe.h"void menu()
{printf("--------------------------------------------------------------\n");printf("---------   1、增加联系人       2、删除指定联系人    ---------\n");printf("---------   3、修改联系人信息   4、查找联系人        ---------\n");printf("---------   5、排序联系人       6、显示已有联系人    ---------\n");printf("---------   0、退出并保存信息   7、清空联系人        ---------\n");printf("--------------------------------------------------------------\n");
}int main()
{int input = 0;//创建通讯录struct contact con;//初始化通讯录(读之前通讯录的信息)Init_contact(&con);do{menu();printf("请选择:->");scanf("%d", &input);system("cls");switch (input){case 1://增加联系人Add_contact(&con);break;case 2://删除联系人Show_contact(&con);Dele_contact(&con);break;case 3://修改联系人信息Show_contact(&con);revise_contact(&con);break;case 4://查找联系人信息Find_contact(&con);break;case 5://排序联系人信息Show_contact(&con);Sort_contact(&con);break;case 6://显示联系人system("cls");Show_contact(&con);printf("\n");break;case 7://清空联系人Clean(&con);break;case 0://保存数据Storage_Contact(&con);//释放空间Destory_contact(&con);break;default:printf("输入错误!\n");break;}} while (input);return 0;
}

相关内容

热门资讯

招商港口高管变更,刘利兵辞任总... 雷达财经 文|冯秀语 编|李亦辉 12月30日,招商局港口集团股份有限公司(证券简称:招商港口,证券...
原创 吉... 吉利把欣旺达给告了,索赔超23亿元! 12月26日晚间,欣旺达发布公告称,公司子公司欣旺达动力在2...
特朗普称明年1月公布美联储主席... 据新华社消息,美国总统特朗普29日说,他预计明年1月宣布美国联邦储备委员会主席鲍威尔的继任人选。 鲍...
吉利起诉欣旺达——大厂自己造电... 导语 从合资建厂到对簿公堂,昔日伙伴反目,背后是中国新能源汽车行业权力游戏的根本性转变。 近日,一则...
2026年“两新”政策部署来了 优化支持范围!2026年“两新”政策部署来了 新华社北京12月30日电(记者魏玉坤、魏弘毅)国家发展...
也迪律师说法:员工被登记为分公... 紫金财经12月30日消息 某信息咨询公司的股东为刘某(持股95%)、张某(持股5%),后公司在多个省...
三部门就《中华人民共和国增值税... 2025年12月25日,国务院总理李强签署第826号国务院令,公布《中华人民共和国增值税法实施条例》...
广发银行汕头分行开展案防形势分... 近日,广发银行汕头分行召开2025年下半年案防工作会议暨案防形势分析会,并同步举办法律知识培训。分行...
“两新”政策优化,为扩内需注入... 备受期待的2026年“国补”来了。 中央经济工作会议明确定调,“坚持内需主导,建设强大国内市场”是2...
2026年“国补”政策来了! 国家发展改革委、财政部印发的《关于2026年实施大规模设备更新和消费品以旧换新政策的通知》30日对外...