一、前言
二、改进思路
无论是静态版本,还是动态版本的通讯录,数据都是放在内存中的,因此当程序退出后,通讯录中的数据就不存在了。
当需要将数据持久化时,就可以使用文件相关的操作(万字详解 C 语言文件操作)。
三、 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. Show 6. Sort *****\n");
printf("***** 7. Cls 0. Exit *****\n");
printf("********************************\n");
}
enum Option
{
EXIT,
ADD,
DEL,
SEARCH,
MODIFY,
SHOW,
SORT,
CLS
};
int main()
{
int input = 0;
Contact con;
ContactInit(&con);
ContactLoad(&con);
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case ADD:
ContactAdd(&con);
break;
case DEL:
ContactDel(&con);
break;
case SEARCH:
ContactSearch(&con);
break;
case MODIFY:
ContactModify(&con);
break;
case SHOW:
ContactShow(&con);
break;
case SORT:
ContactSort(&con);
break;
case CLS:
system("cls");
break;
case EXIT:
ContactSave(&con);
// 使用了动态开辟的内存,就需要主动释放
free(con.data);
con.data = NULL;;
printf("退出通讯录~\n");
break;
default:
printf("选择错误,请重新选择!\n");
break;
}
} while (input);
return 0;
}
四、contact.h
#pragma once
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define DEFAULT_SIZE 5 // 容量的默认大小
#define INCREMENT 5 // 扩容的增量
// 类型的声明
typedef struct PeoInfo
{
char name[20];
int age;
char gender[10];
char addr[20];
char tel[15];
}PeoInfo;
typedef struct Contact
{
PeoInfo* data;
int count; // 不仅能表示当前通讯录中的人数,还能表示能存放联系人信息的数组下标
int capacity; // 容量,即表示当前通讯录最多能存放多少联系人的信息
}Contact;
// 函数的声明
void ContactInit(Contact* pc); // 初始化通讯录
void ContactLoad(Contact* pc); // 加载通讯录的数据
void ContactShow(const Contact* pc); // 5 - 显示所有的联系人
void ContactAdd(Contact* pc); // 1 - 添加联系人
void ContactDel(Contact* pc); // 2 - 删除联系人
void ContactSearch(const Contact* pc); // 3 - 查找联系人
void ContactModify(Contact* pc); // 4 - 修改联系人
void ContactSort(Contact* pc); // 6 - 对通讯录进行排序(按名字进行排序)
void ContactSave(Contact* pc); // 保存通讯录
五、contact.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "contact.h"
// 初始化通讯录
void ContactInit(Contact* pc)
{
pc->count = 0;
pc->capacity = DEFAULT_SIZE;
pc->data = (PeoInfo*)calloc(pc->capacity, sizeof(PeoInfo));
if (NULL == pc->data)
{
perror("Initialization failed!");
exit(1);
}
}
// 加载通讯录的数据
void ContactLoad(Contact* pc)
{
FILE* fp = fopen("contact.txt", "rb");
if (NULL == fp)
{
perror("Load failed for fopen!");
exit(1);
}
PeoInfo tmp = { 0 };
for (int i = 0; fread(&tmp, sizeof(PeoInfo), 1, fp); i++)
{
if (pc->count == pc->capacity)
{
PeoInfo* ret = (PeoInfo*)realloc(pc->data, (pc->capacity + INCREMENT) * sizeof(PeoInfo));
if (NULL == ret)
{
perror("Load failed for realloc!");
exit(1);
}
pc->data = ret;
pc->capacity += INCREMENT;
ret = NULL;
}
pc->data[i] = tmp;
pc->count++;
}
fclose(fp);
fp = NULL;
}
// 5 - 显示所有的联系人
void ContactShow(const Contact* pc)
{
printf("%-20s %-4s %-10s %-20s %-15s\n", "姓名", "年龄", "性别", "家庭住址", "电话号码");
for (int i = 0; i < pc->count; i++)
{
printf("%-20s %-4d %-10s %-20s %-15s\n",
pc->data[i].name,
pc->data[i].age,
pc->data[i].gender,
pc->data[i].addr,
pc->data[i].tel
);
}
}
// 1 - 添加联系人
void ContactAdd(Contact* pc)
{
if (pc->count == pc->capacity)
{
PeoInfo* tmp = (PeoInfo*)realloc(pc->data, (pc->capacity + INCREMENT) * sizeof(PeoInfo));
if (NULL == tmp)
{
printf("扩容失败,无法再添加联系人!\n");
return;
}
pc->data = tmp;
pc->capacity += INCREMENT;
tmp = NULL;
}
printf("请输入联系人的姓名:>");
scanf("%s", pc->data[pc->count].name);
printf("请输入联系人的年龄:>");
scanf("%d", &pc->data[pc->count].age);
printf("请输入联系人的性别:>");
scanf("%s", pc->data[pc->count].gender);
printf("请输入联系人的家庭住址:>");
scanf("%s", pc->data[pc->count].addr);
printf("请输入联系人的电话号码:>");
scanf("%s", pc->data[pc->count].tel);
pc->count++;
printf("添加成功~\n");
}
// 通过联系人的姓名找到其在数组中对应的下标
static FindByName(const Contact* pc, char name[])
{
for (int i = 0; i < pc->count; i++)
{
if (strcmp(pc->data[i].name, name) == 0)
{
return i;
}
}
return -1;
}
// 2 - 删除联系人
void ContactDel(Contact* pc)
{
if (pc->count == 0)
{
printf("通讯录为空!\n");
return;
}
char name[20];
printf("请输入待删除的联系人的姓名:>");
scanf("%s", name);
int pos = FindByName(pc, name);
if (pos == -1)
{
printf("该联系人不存在!\n");
return;
}
else
{
for (int i = pos + 1; i < pc->count; i++)
{
pc->data[i - 1] = pc->data[i];
}
pc->count--;
printf("删除成功~\n");
}
}
// 3 - 查找联系人
void ContactSearch(const Contact* pc)
{
char name[20];
printf("请输入待查找的联系人的姓名:>");
scanf("%s", name);
int pos = FindByName(pc, name);
if (pos == -1)
{
printf("该联系人不存在!\n");
return;
}
else
{
printf("%-20s %-4s %-10s %-20s %-15s\n", "姓名", "年龄", "性别", "家庭住址", "电话号码");
printf("%-20s %-4d %-10s %-20s %-15s\n",
pc->data[pos].name,
pc->data[pos].age,
pc->data[pos].gender,
pc->data[pos].addr,
pc->data[pos].tel
);
}
}
// 4 - 修改联系人
void ContactModify(Contact* pc)
{
char name[20];
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].gender);
printf("请重新输入该联系人的家庭住址:>");
scanf("%s", pc->data[pos].addr);
printf("请重新输入该联系人的电话号码:>");
scanf("%s", pc->data[pos].tel);
printf("修改成功~\n");
}
}
// 6 - 按联系人的姓名对通讯录进行排序
int cmp_by_name(const void* e1, const void* e2)
{
return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name);
}
void ContactSort(Contact* pc)
{
qsort(pc->data, pc->count, sizeof(PeoInfo), cmp_by_name);
printf("排序成功~\n");
}
// 保存通讯录
void ContactSave(Contact* pc)
{
FILE* fp = fopen("contact.txt", "wb");
if (NULL == fp)
{
perror("Save failed!");
return;
}
for (int i = 0; i < pc->count; i++)
{
fwrite(pc->data + i, sizeof(PeoInfo), 1, fp);
}
fclose(fp);
fp = NULL;
printf("通讯录已保存~\n");
}