目录
1、为什么改成文件版
我们之前写的通讯录运行起来的时候,可以给通讯录中增加、删除数据,此时数据是存放在内存中,当程序退出的时候,通讯录中的数据自然就不存在了,等下次运行通讯录程序的时候,数据又得重新录入,如果使用这样的通讯录就很难受。
而使用文件我们可以将数据直接存放在电脑的硬盘上,做到了数据的持久化,因而改成文件版。
- 主要实现两个目标:
- 当通讯录退出的时候,把信息写到文件
- 当通讯录初始化的时候,加载文件的信息到通讯录中
2、改动之处
(1)保存信息到文件
- contact.h 文件:
//保存通讯录信息到文件 void SaveContact(Contact* pc);
- contact.c 文件:
//保存信息到文件 void SaveContact(Contact* pc) { //打开文件 FILE* pf = fopen("contact.txt", "w"); if (pf == NULL) { perror("SaveContact"); return; } //写文件 int i = 0; for (i = 0; i < pc->sz; i++) { fwrite(pc->data + i, sizeof(PeoInfo), 1, pf); } //关闭文件 fclose(pf); pf = NULL; }
(2)将增容编写成函数
- contact.h 文件:
//检测是否需要增容 void CheckCapacity(Contact* pc);
- contact.c 文件:
//考虑增容的函数 void CheckCapacity(Contact* pc) { if (pc->sz == pc->capacity) { PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + INC_SZ) * sizeof(PeoInfo)); if (ptr != NULL) { pc->data = ptr; pc->capacity += INC_SZ; printf("增容成功\n"); } else { perror("AddConract"); printf("增加联系人失败\n"); return; } } }
(3)初始化里加载文件
- contact.h 文件:
//加载文件内容到通讯录 void LoadContact(Contact* pc);
- contact.c 文件:
void LoadContact(Contact* pc) { FILE* pf = fopen("contact.txt", "r"); 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; }
3、完整代码
(1)test.c 文件
#define _CRT_SECURE_NO_WARNINGS 1 #include"contact.h" void menu() { printf("*******************************************\n"); printf("******* 1. add 2. del *********\n"); printf("******* 3. search 4. modify *********\n"); printf("******* 5. sort 6. print *********\n"); printf("******* 0. exit *********\n"); printf("*******************************************\n"); } enum Option { EXIT, ADD, DEL, SEARCH, MODIFY, SORT, PRINT }; int main() { int input = 0; //创建通讯录 Contact con;//通讯录 //初始化通讯录 //给data申请一块连续的空间在堆上 //sz=0 //capacity初始化为当前最大的容量 InitContact(&con); do { menu(); printf("请选择:>"); 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 SORT: //排序 SortContact(&con); break; case PRINT: //打印 PrintContact(&con); break; case EXIT: //退出 //保存信息到文件 SaveContact(&con); //销毁通讯录 DestoryContact(&con); printf("退出通讯录\n"); break; default: printf("选择错误,重新选择\n"); break; } } while (input); return 0; }
(2)contact.h 文件
#pragma once
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAX_NAME 20
#define MAI_SEX 10
#define MAX_TELE 12
#define MAX_ADDR 30
#define MAX 1000
#define DEFAULT_SZ 3
#define INC_SZ 2
//存放每个人的信息
typedef struct PeoInfo
{
char name[MAX_NAME];
char sex[MAI_SEX];
int age;
char tele[MAX_TELE];
char addr[MAX_ADDR];
}PeoInfo;
//创建通讯录
typedef struct Contact
{
PeoInfo* data; //指向动态申请的空间,用来存放联系人的信息
int sz; //记录当前通讯录中有效信息的个数
int capacity; //记录当前通讯录的最大容量
}Contact;
//初始化通讯录
void InitContact(Contact* pc);
//增加联系人
void AddContact(Contact* pc);
//打印联系人信息
void PrintContact(const Contact* pc);
//删除联系人信息
void DelContact(Contact* pc);
//查找指定联系人
void SearchContact(Contact* pc);
//修改指定联系人
void ModifyContact(Contact* pc);
//排序联系人
void SortContact(Contact* ps);
//销毁通讯录
void DestoryContact(Contact* pc);
//保存通讯录信息到文件
void SaveContact(Contact* pc);
//加载文件内容到通讯录
void LoadContact(Contact* pc);
//检测是否需要增容
void CheckCapacity(Contact* pc);
(3)contact.c 文件
#define _CRT_SECURE_NO_WARNINGS 1 #include"contact.h" void LoadContact(Contact* pc) { FILE* pf = fopen("contact.txt", "r"); 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) { pc->data = (PeoInfo*)malloc(DEFAULT_SZ * sizeof(PeoInfo)); if (pc->data == NULL) { perror("InitContact"); return; } pc->sz = 0; //初始化后默认是0,一个元素都没 pc->capacity = DEFAULT_SZ; //加载文件 LoadContact(pc); } //考虑增容的函数 void CheckCapacity(Contact* pc) { if (pc->sz == pc->capacity) { PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + INC_SZ) * sizeof(PeoInfo)); if (ptr != NULL) { pc->data = ptr; pc->capacity += INC_SZ; printf("增容成功\n"); } else { perror("AddConract"); printf("增加联系人失败\n"); return; } } } //动态版本-添加联系人 void AddContact(Contact* 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].sex); printf("请输入电话:>"); scanf("%s", pc->data[pc->sz].tele); printf("请输入地址:>"); scanf("%s", pc->data[pc->sz].addr); pc->sz++; printf("增加成功\n"); } //打印联系人信息 void PrintContact(const Contact* pc) { if (pc->sz == 0) { printf("通讯录为空!\n"); return; } int i = 0; //打印标题 printf("%-12s\t%-5s\t%-5s\t%-12s\t%-20s\n", "名字", "年龄", "性别", "电话", "地址"); //打印数据 for (i = 0; i < pc->sz; i++) { printf("%-12s\t%-5d\t%-5s\t%-12s\t%-20s\n", pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr ); } } //查找要删除的联系人 static int FindByName(Contact* pc, char name[]) { int i = 0; for (i = 0; i < pc->sz; i++) { if (strcmp(pc->data[i].name, name) == 0) { return i; } } return -1; //找不到 } //删除联系人信息 void DelContact(Contact* pc) { char name[MAX_NAME] = { 0 }; if (pc->sz == 0) { printf("通讯录为空,无需删除\n"); return; } printf("请输入要删除人的名字:>"); scanf("%s", name); //1、得先查找要删除的人 //有/没有 int pos = FindByName(pc, name); if (pos == -1) { printf("要删除的人不存在\n"); return; } //2、删除 int i = 0; for (i = pos; i < pc->sz - 1; i++) { pc->data[i] = pc->data[i + 1]; } pc->sz--; printf("删除成功\n"); } //查找指定联系人 void SearchContact(Contact* pc) { char name[MAX_NAME] = { 0 }; printf("请输入要查找人的名字:>"); scanf("%s", name); int pos = FindByName(pc, name); if (pos == -1) { printf("要查找的人不存在\n"); return; } else { int i = 0; //打印标题 printf("%-12s\t%-5s\t%-5s\t%-12s\t%-20s\n", "名字", "年龄", "性别", "电话", "地址"); //打印数据 printf("%-12s\t%-5d\t%-5s\t%-12s\t%-20s\n", pc->data[pos].name, pc->data[pos].age, pc->data[pos].sex, pc->data[pos].tele, pc->data[pos].addr); } } //修改指定联系人 void ModifyContact(Contact* pc) { char name[MAX_NAME] = { 0 }; printf("请输入要修改人的名字:>"); scanf("%s", name); int pos = FindByName(pc, name); if (pos == -1) { printf("要修改的人不存在\n"); return; } else { 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); printf("修改成功\n"); } } //通过姓名排序 int CmpByName(const void* e1, const void* e2) { return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name); } //通过年龄排序 int CmpByAge(const void* e1, const void* e2) { return ((PeoInfo*)e1)->age - ((PeoInfo*)e2)->age; } //排序通讯录中联系人的先后顺序 void SortContact(Contact* ps) { int input = 0; printf("1、姓名\t2、年龄\n"); printf("请选择你要排序的方式:>"); scanf("%d", &input); switch (input) { case 1: qsort(ps->data, ps->sz, sizeof(PeoInfo), CmpByName);//排序 printf("排序成功\n"); break; case 2: qsort(ps->data, ps->sz, sizeof(PeoInfo), CmpByAge);//排序 printf("排序成功\n"); break; default: printf("请输入有效数字\n"); } } //销毁通讯录 void DestoryContact(Contact* pc) { free(pc->data); pc->data = NULL; pc->sz = 0; pc->capacity = 0; } //保存信息到文件 void SaveContact(Contact* pc) { //打开文件 FILE* pf = fopen("contact.txt", "w"); if (pf == NULL) { perror("SaveContact"); return; } //写文件 int i = 0; for (i = 0; i < pc->sz; i++) { fwrite(pc->data + i, sizeof(PeoInfo), 1, pf); } //关闭文件 fclose(pf); pf = NULL; }
- 运行结果:
假设我们先前添加了几个信息:
此时退出通讯录
当我们下次再打开时: