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

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


目录

  • 一. 保存通讯录到文件中
  • 二. 在程序开始时加载文件信息到通讯录
  • 三. 模块化代码实现
    • 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.Select4.Modify ******\n");printf("******5.Show6.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#include#include#include#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 2typedef 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个联系人的信息,所以显示增容成功


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