我们在之前的博客中已经写过两版通讯录了:
第一版是用C语言实现了通讯录,但是通讯录的存储人数信息是固定的,用完就没有了
感兴趣的可以转到对应博客看一下,附带链接:第一版通讯录
第二版是在第一版的基础上动态开辟内存,使这个通讯录可以无限(只有内存足够大)存储人的信息
感兴趣的可以转到对应博客看一下,附带链接:第二版通讯录
今天我们要实现的是第三版,建立在第二版的基础上,将写入通讯录的人的信息保存在文件中
这里附带我们讲解文件操作的链接,不了解的小伙伴可以先去看一下文件操作:C语言之文件操作
我们前两版的通讯录只要结束了程序我们之前存入内存的数据就都被销毁了,是没办法保存下来的,下次运行程序我们还得重新存入这部分人的信息,这样是很不方便的。但是我们现在已经学习了文件操作这部分知识,我们现在可以做到把已经写入通讯录中人的信息保存到文件中,也就是硬盘中,当我们结束通讯录程序的代码执行,这些人的信息依旧是存在的,我们只要打开对应文件就可以看到,下次想要在存入人的信息,可以直接存入别人的信息,不用在存入已经存入的人的信息!
我们在这篇里是不会详细介绍它这样写的原理的,因为这部分讲解在实现第一版通讯录就已经说的很清楚了。
好,现在交代清楚了,我们话不多说,上代码!!!
目录
test .c
Contact.c
Contact.h
运行结果展示
test .c
//实现将通讯录数据写入文件中(硬盘中)实现数据的永久保存 //里面存放人的信息,包括姓名,年龄,性别 //实现的通讯录功能有: //电话号码和家庭住址 //结合枚举,必要时要增容 //它包括以下功能 //1.增加联系人 //2.删除指定联系人 //3.查找指定联系人 //4.修改指定联系人 //5.显示所有联系人 //6.对所有联系人进行排序(按姓名) //7.退出通讯录(这时要记得释放动态内存开辟的空间,避免内存泄漏 #include"contact.h" //加入枚举,给下面Switch case语句一个提示,函数写到了通讯录的哪个功能 enum contact { exitContact, addContact, delContact, showContact, sehContact, mofContact, sortContact, }; void menu(void) { printf("*******************************************\n"); printf("********** 1.AddContact **********\n"); printf("********** 2.DelContact **********\n"); printf("********** 3.ShowContact **********\n"); printf("********** 4.SehContact **********\n"); printf("********** 5.MofContact **********\n"); printf("********** 6.SortContact **********\n"); printf("********** 0.ExitContact **********\n"); printf("*******************************************\n"); } int main() { int input = 0; Contact con; //初始化通讯录 InitContact(&con); do { menu(); printf("请选择:>"); scanf("%d", &input); switch (input) { case addContact: AddContact(&con); break; case delContact: DelContact(&con); break; case showContact: ShowContact(&con); break; case sehContact: SehContact(&con); break; case mofContact: MofContact(&con); break; case sortContact: SortContact(&con); break; case exitContact: //把通讯录数据存入文件中 SaveContact(&con); //销毁通讯录,进行动态空间的释放 DestoryContact(&con); break; default: printf("输入错误,请重新输入!\n"); break; } } while (input); return 0; }
Contact.c
#include"contact.h" //空间增容函数 void check_capacity(Contact* pc) { assert(pc); if (pc->sz == pc->capacity) { //通讯录已满,进行增容 PeopInfo* str = (PeopInfo*)realloc(pc->data, (pc->capacity + INC_SZ) * sizeof(PeopInfo)); if (str == NULL) { perror("realloc"); return; } pc->data = str; pc->capacity += INC_SZ;//总容量增加 printf("空间增容成功,可以继续添加联系人\n"); } } //通过名字查找 int FindByName(const Contact* pc, char* Name) { assert(pc); int i = 0; if (pc->sz == 0) { printf("通讯录为空,无法查找!"); return; } for (i = 0; i < pc->sz; i++) { if (strcmp(Name, pc->data[i].Name) == 0) return i; } return -1; } //初始化这个通讯录,初始化为对应的值,每次打开通讯录上次存入文件的信息 //都不会被覆盖,增加一个函数功能,加载文件信息到通讯录 void InitContact(Contact* pc) { assert(pc); //为通讯录存放人的信息的结构体分配初始空间,并把里面数据直接 //初始化为0,calloc函数很合适 PeopInfo* str = (PeopInfo*)calloc(DEFAULT_SZ, sizeof(PeopInfo)); if (str == NULL) { perror("calloc"); return; } pc->data = str; pc->sz = 0; pc->capacity = DEFAULT_SZ; //加载文件中的信息到通讯录 LoadContact(pc); } //加载文件中的信息到通讯录 void LoadContact(Contact* pc) { assert(pc); //从文件中读取通讯录数据 FILE* pf = fopen("Contact.txt", "rb"); if (pf == NULL) { perror("LoadContact"); return; } //读数据 PeopInfo tmp = { 0 };//存放读到的数据 int i = 0; while (fread(&tmp,sizeof(PeopInfo),1,pf)) { //增容问题 check_capacity(pc); pc->data[i] = tmp; pc->sz++; i++; } //读取完毕,关闭文件 fclose(pf); pf = NULL; } //把通讯录数据存入文件中 void SaveContact(Contact* pc) { assert(pc); //写数据 //以二进制打开文件写入 FILE* pf = fopen("Contact.txt", "wb"); if (pf == NULL) { perror("SaveContact"); return; } //开始写入 int i = 0; for (i = 0; i < pc->sz; i++) { //这里大家可以自己尝试一下,fprintf和fputs 是否可以写入数据 fwrite(pc->data + i, sizeof(PeopInfo), 1, pf); } //关闭文件 fclose(pf); pf = NULL; printf("保存数据成功\n"); } //增加通讯录联系人 void AddContact(Contact* pc) { assert(pc); check_capacity(pc);//检查通讯录是否需要增容 //增加人的信息 printf("请输入联系人姓名:>"); scanf("%s", pc->data[pc->sz].Name); printf("请输入联系人年龄:>"); scanf("%d", &pc->data[pc->sz].Age); printf("请输入联系人性别:>"); scanf("%s", pc->data[pc->sz].Sex); printf("请输入联系人电话号码:>"); scanf("%s", pc->data[pc->sz].Tele); printf("请输入联系人家庭住址:>"); scanf("%s", pc->data[pc->sz].Addr); pc->sz++; } //删除指定联系人 void DelContact(Contact* pc) { assert(pc); char Name[NAME_MAX] = { 0 }; int i = 0; if (pc->sz == 0) { printf("通讯录为空,无法删除!\n"); return; } printf("请输入要删除的人的姓名:>"); scanf("%s", Name); int pos = FindByName(pc, Name); if (pos == -1) { printf("要删除的联系人不存在!\n"); return; } for (i = pos; i < pc->sz - 1; i++) { pc->data[i] = pc->data[i + 1]; } pc->sz--; printf("删除联系人成功!\n"); } //显示所有联系人 void ShowContact(const Contact* pc) { assert(pc); if (pc->sz == 0) { printf("通讯录为空,无法显示!\n"); return; } int i = 0; printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话号码", "家庭住址"); for (i = 0; i < pc->sz; i++) { printf("%-20s\t%-4d\t%-5s\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); } } //查找指定联系人 void SehContact(const Contact* pc) { assert(pc); if (pc->sz == 0) { printf("通讯录为空,无法查找!\n"); return; } char Name[NAME_MAX] = { 0 }; printf("请输入要查找的人的姓名:>"); scanf("%s", Name); int pos = FindByName(pc, Name); if (pos == -1) { printf("要查找的联系人不存在!\n"); return; } printf("%-20s\t%-4s\t%-5s\t%-12s\t%-30s\n", "姓名", "年龄", "性别", "电话号码", "家庭住址"); printf("%-20s\t%-4d\t%-5s\t%-12s\t%-30s\n", pc->data[pos].Name, pc->data[pos].Age, pc->data[pos].Sex, pc->data[pos].Tele, pc->data[pos].Addr); } //修改指点联系人的信息 void MofContact(Contact* pc) { assert(pc); if (pc->sz == 0) { printf("通讯录为空,无法修改!\n"); return; } char Name[NAME_MAX] = { 0 }; printf("请输入要修改的人的姓名:>"); scanf("%s", Name); int pos = FindByName(pc, Name); if (pos == -1) { printf("要修改的联系人不存在!\n"); return; } printf("请输入联系人姓名:>"); scanf("%s", pc->data[pos].Name); printf("请输入联系人年龄:>"); scanf("%d", &pc->data[pos].Age); printf("请输入联系人性别:>"); scanf("%s", pc->data[pos].Sex); printf("请输入联系人电话号码:>"); scanf("%s", pc->data[pos].Tele); printf("请输入联系人家庭住址:>"); scanf("%s", pc->data[pos].Addr); } //对所有联系人按姓名进行排序 void SortContact(const Contact* pc) { assert(pc); int i = 0; int j = 0; for (i = 0; i < pc->sz; i++) { for (j = i; j < pc->sz; j++) { if (strcmp(pc->data[i].Name, pc->data[j].Name) > 0) { PeopInfo temp[] = { 0 }; temp[0] = pc->data[i]; pc->data[i] = pc->data[j]; pc->data[j] = temp[0]; } } } ShowContact(pc);//显示一下排列结果 } //销毁通讯录,释放动态内存空间 void DestoryContact(Contact* pc) { free(pc->data); pc->data = NULL; pc->sz = 0; pc->capacity = 0; pc = NULL; printf("通讯录已退出\n"); }
Contact.h
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<stdlib.h> #include<string.h> #include<errno.h> #include<assert.h> #define DEFAULT_SZ 3 //初始通讯录内存放的联系人个数 #define INC_SZ 2 //每次增容的空间 #define NAME_MAX 30 #define SEX_MAX 5 #define TELE_MAX 12 #define ADDR_MAX 30 //创建结构体存放有关人的信息 typedef struct PeopInfo { char Name[NAME_MAX]; int Age; char Sex[SEX_MAX]; char Tele[TELE_MAX]; char Addr[ADDR_MAX]; }PeopInfo; //创建初始通讯录,里面存放人的信息,初始内存大小 typedef struct Contact { PeopInfo* data; //存放人的信息 int sz; int capacity; //初始内存 }Contact; //空间增容函数 void check_capacity(Contact* pc); //初始化这个通讯录,初始化为对应的值 void InitContact(Contact* pc); //增加通讯录联系人 void AddContact(Contact* pc); //删除指定联系人 void DelContact(Contact* pc); //显示所有联系人 void ShowContact(const Contact* pc); //通过名字查找 int FindByName(const Contact* pc, char* Name); //查找指定联系人 void SehContact(const Contact* pc); //修改指点联系人的信息 void MofContact(Contact* pc); //对所有联系人按姓名进行排序 void SortContact(const Contact* pc); //把通讯录数据存入文件中 void SaveContact(Contact* pc); //加载文件中的信息到通讯录 void LoadContact(Contact* pc); //销毁通讯录,释放动态内存空间 void DestoryContact(Contact* pc);
运行结果展示
程序代码上的显示(已经存入数据)
在文件中的显示
总体的代码实现就是这样了,希望大家可以理解哟!
我们下期再见!!!