接下来我们将会使用顺序表来实现通讯录,在此无需做过多说明解释。代码逻辑清晰,条理有序,易于理解。
头文件:
#pragma once
#include
#include
#include
#include
// 用于存储联系人的信息
typedef struct People
{
char address[50];
char name[20];
char tele[20];
char sex[10];
int age;
} People;
typedef struct Contacts
{
People* a;
int size;
int capacity;
}Contacts;
// 枚举常量,便于日后的使用
enum choice { by_name = 1, by_tele, by_address, by_age };
// 一个顺序表,用于存储下标。我们将会在查找函数使用它
typedef struct Index
{
int* a;
int size;
int capacity;
}Index;
// 菜单
void menu1();
void menu2();
void menu3();
void menu4();
// 加载通讯录
void LoadContacts(Contacts* ps);
// 对通讯录进行初始化
void ContactsInit(Contacts* ps);
// 打印通讯录
void ContactsPrint(Contacts ps);
// 添加和删除通讯录成员
void ContactsAdd(Contacts* ps);
void ContactsDelt(Contacts* ps);
// 通讯录查找
void ContactsFind(Contacts ps, int choice, Index* index);
void FIND(Contacts contacts, int choice);
// 修改联系人
void ContactsModify(Contacts* ps, int index);
// 排序联系人
void ContactsSort(Contacts* ps, int choice);
// 保存通讯录
void SaveContact(Contacts* pc);
// 销毁通讯录
void ContactsDestroy(Contacts* ps);
函数的实现:
#include "Contacts.h"
void menu1()
{
printf("**********************************\n");
printf("*** 请按下相应的数字以进行选择 ***\n");
printf("****1.进入通讯录 0.退出通讯录****\n");
printf("**********************************\n");
}
void menu2()
{
printf("**********************************\n");
printf("*** 请按下相应的数字以进行选择 ***\n");
printf("****1.添加联系人 2.删除联系人****\n");
printf("****3.查找联系人 4.修改联系人****\n");
printf("****5.显示联系人 6.清空联系人****\n");
printf("****7.排序联系人 0.退出通讯录****\n");
printf("**********************************\n");
}
void menu3()
{
printf("**********************************\n");
printf("*** 请按下相应的数字以进行选择 ***\n");
printf("**1.按照姓名查找 2.按照号码查找**\n");
printf("**3.按照住址查找 4.按照年龄查找**\n");
printf("**0.退出查找模式 ****************\n");
printf("**********************************\n");
}
void menu4()
{
printf("**********************************\n");
printf("*** 请按下相应的数字以进行选择 ***\n");
printf("**1.按照姓名排序 2.按照号码排序**\n");
printf("**3.按照住址排序 4.按照年龄排序**\n");
printf("**0.退出排序模式 ****************\n");
printf("**********************************\n");
}
// 检查当前顺序表是否已经满了
static void CheckCapacity(Contacts* ps)
{
assert(ps);
if (ps->size == ps->capacity)
{
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
People* tmp = (People*)realloc(ps->a, sizeof(People) * newcapacity);
if (tmp == NULL)
{
perror("realloc fail");
return;
}
ps->a = tmp;
ps->capacity = newcapacity;
}
}
// 将通讯录信息从文件加载到顺序表中
void LoadContacts(Contacts* ps)
{
FILE* pf = fopen("contact.txt", "rb");
if (pf == NULL)
{
perror("LoadContact");
return;
}
//读文件
People tmp;
while (fread(&tmp, sizeof(People), 1, pf))
{
CheckCapacity(ps);
ps->a[ps->size] = tmp;
ps->size++;
}
fclose(pf);
pf = NULL;
}
// 初始化通讯录
void ContactsInit(Contacts* ps)
{
assert(ps);
ps->a = NULL;
ps->size = 0;
ps->capacity = 0;
}
// 打印联系人
void ContactsPrint(Contacts ps)
{
int i = 0;
for (i = 0; i < ps.size; ++i)
{
printf("姓名:%-8s", (ps.a[i]).name);
printf("住址:%-8s", (ps.a[i]).address);
printf("电话:%-8s", (ps.a[i]).tele);
printf("性别:%-8s", (ps.a[i]).sex);
printf("年龄:%-8d", (ps.a[i]).age);
printf("\n\n");
}
}
// 顺序表的添加
// 需要注意fgets需要自己手动添加'\0'
void ContactsAdd(Contacts* ps)
{
assert(ps);
while (getchar() != '\n');//清空缓存区
CheckCapacity(ps);
printf("请输入联系人姓名:");
fgets(ps->a[ps->size].name, sizeof(ps->a->name), stdin);
if (ps->a[ps->size].name[strlen(ps->a[ps->size].name) - 1] == '\n')
{
ps->a[ps->size].name[strlen(ps->a[ps->size].name) - 1] = '\0';
}
printf("请输入联系人住址:");
fgets(ps->a[ps->size].address, sizeof(ps->a->address), stdin);
if (ps->a[ps->size].address[strlen(ps->a[ps->size].address) - 1] == '\n')
{
ps->a[ps->size].address[strlen(ps->a[ps->size].address) - 1] = '\0';
}
printf("请输入联系人电话:");
fgets(ps->a[ps->size].tele, sizeof(ps->a->tele), stdin);
if (ps->a[ps->size].tele[strlen(ps->a[ps->size].tele) - 1] == '\n')
{
ps->a[ps->size].tele[strlen(ps->a[ps->size].tele) - 1] = '\0';
}
printf("请输入联系人性别:");
fgets(ps->a[ps->size].sex, sizeof(ps->a->sex), stdin);
if (ps->a[ps->size].sex[strlen(ps->a[ps->size].sex) - 1] == '\n')
{
ps->a[ps->size].sex[strlen(ps->a[ps->size].sex) - 1] = '\0';
}
printf("请输入联系人年龄:");
scanf("%d", &(ps->a[ps->size].age));
ps->size++;
}
// 删除联系人
void ContactsDelt(Contacts* ps)
{
assert(ps);
if (ps->size)
{
ps->size--;
}
return;
}
// 一个用于存储下标的顺序表,用于查找联系人时,
// 将多个符合条件的联系人的下标存储起来。
static void IndexInit(Index* ps)
{
assert(ps);
ps->a = NULL;
ps->size = 0;
ps->capacity = 0;
}
// 下标的添加
static void IndexAdd(Index* ps, int x)
{
assert(ps);
if (ps->size == ps->capacity)
{
int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
int* tmp = (int*)realloc(ps->a, sizeof(int) * newcapacity);
if (tmp == NULL)
{
perror("realloc fail");
return;
}
ps->a = tmp;
ps->capacity = newcapacity;
}
ps->a[ps->size] = x;
ps->size++;
}
// 下标顺序表的销毁
static void IndexDestroy(Index* ps)
{
assert(ps);
if (ps->a != NULL)
{
free(ps->a);
ps->a = NULL;
ps->size = 0;
ps->capacity = 0;
}
}
void ContactsFind(Contacts ps, int choice, Index* index)
{
int count = 0;
int i = 0;
char arr[50];
int age = 0;
while (getchar() != '\n');
switch (choice)
{
case by_name:
printf("请输入要查找的姓名:");
fgets(arr, sizeof(arr), stdin);
if (arr[strlen(arr) - 1] == '\n')
{
arr[strlen(arr) - 1] = '\0';
}
for (int i = 0; i < ps.size; i++)
{
if (strcmp(ps.a[i].name, arr) ==0)
{
IndexAdd(index, i);
}
}
break;
case by_tele:
printf("请输入要查找的号码:");
fgets(arr, sizeof(arr), stdin);
if (arr[strlen(arr) - 1] == '\n')
{
arr[strlen(arr) - 1] = '\0';
}
for (int i = 0; i < ps.size; i++)
{
if (strcmp(ps.a[i].tele, arr) == 0)
{
IndexAdd(index, i);
}
}
break;
case by_address:
printf("请输入要查找的住址:");
fgets(arr, sizeof(arr), stdin);
if (arr[strlen(arr) - 1] == '\n')
{
arr[strlen(arr) - 1] = '\0';
}
for (int i = 0; i < ps.size; i++)
{
if (strcmp(ps.a[i].address, arr) == 0)
{
IndexAdd(index, i);
}
}
break;
case by_age:
printf("请输入要查找的年龄:");
scanf("%d", &age);
for (i = 0; i < ps.size; ++i)
{
if (ps.a[i].age == age);
{
IndexAdd(index, i);
}
}
}
}
// 查找联系人
void FIND(Contacts contacts, int choice)
{
if (choice < 0 || choice >4)
{
printf("选择错误,请重新选择!!!\n");
return;
}
// 创建用于存储下标的顺序表并初始化。使用完毕记得销毁。
Index index;
IndexInit(&index);
ContactsFind(contacts, choice, &index);
printf("共查找到%d个联系人:\n", index.size);
for (int i = 0; i < index.size; ++i)
{
printf("第%d个联系人: ", index.a[i] + 1);
printf("姓名:%-8s", (contacts.a[index.a[i]]).name);
printf("住址:%-8s", (contacts.a[index.a[i]]).address);
printf("电话:%-8s", (contacts.a[index.a[i]]).tele);
printf("性别:%-8s", (contacts.a[index.a[i]]).sex);
printf("年龄:%-8d", (contacts.a[index.a[i]]).age);
printf("\n\n");
}
IndexDestroy(&index);
}
void ContactsModify(Contacts* ps, int index)
{
assert(ps);
while (getchar() != '\n');//清空缓存区
printf("请输入联系人姓名:");
fgets(ps->a[index - 1].name, sizeof(ps->a->name), stdin);
if (ps->a[index - 1].name[strlen(ps->a[index - 1].name) - 1] == '\n')
{
ps->a[index - 1].name[strlen(ps->a[index - 1].name) - 1] = '\0';
}
printf("请输入联系人住址:");
fgets(ps->a[index - 1].address, sizeof(ps->a->address), stdin);
if (ps->a[index - 1].address[strlen(ps->a[index - 1].address) - 1] == '\n')
{
ps->a[index - 1].address[strlen(ps->a[index - 1].address) - 1] = '\0';
}
printf("请输入联系人电话:");
fgets(ps->a[index - 1].tele, sizeof(ps->a->tele), stdin);
if (ps->a[index - 1].tele[strlen(ps->a[index - 1].tele) - 1] == '\n')
{
ps->a[index - 1].tele[strlen(ps->a[index - 1].tele) - 1] = '\0';
}
printf("请输入联系人性别:");
fgets(ps->a[index - 1].sex, sizeof(ps->a->sex), stdin);
if (ps->a[index - 1].sex[strlen(ps->a[index - 1].sex) - 1] == '\n')
{
ps->a[index - 1].sex[strlen(ps->a[index - 1].sex) - 1] = '\0';
}
printf("请输入联系人年龄:");
scanf("%d", &(ps->a[index - 1].age));
}
// 比较函数,用于qsort
int compare_by_name(const void* a, const void* b)
{
return strcmp(((People*)a)->name, ((People*)b)->name);
}
int compare_by_tele(const void* a, const void* b)
{
return strcmp(((People*)a)->tele, ((People*)b)->tele);
}
int compare_by_address(const void* a, const void* b)
{
return strcmp(((People*)a)->address, ((People*)b)->address);
}
int compare_by_age(const void* a, const void* b)
{
return ((People*)a)->age - ((People*)b)->age;
}
void ContactsSort(Contacts* ps, int choice)
{
switch (choice)
{
case by_name:
qsort(ps->a, ps->size, sizeof(People), compare_by_name);
break;
case by_tele:
qsort(ps->a, ps->size, sizeof(People), compare_by_tele);
break;
case by_address:
qsort(ps->a, ps->size, sizeof(People), compare_by_address);
break;
case by_age:
qsort(ps->a, ps->size, sizeof(People), compare_by_age);
break;
default:
printf("输入错误!");
}
}
void SaveContact(Contacts* pc)
{
FILE* pf = fopen("contact.txt", "wb");
if (pf == NULL)
{
perror("SaveContacts");
return;
}
//写信息到文件
int i = 0;
for (i = 0; i < pc->size; i++)
{
fwrite(pc->a + i, sizeof(People), 1, pf);
}
fclose(pf);
pf = NULL;
}
void ContactsDestroy(Contacts* ps)
{
assert(ps);
if (ps->a != NULL)
{
free(ps->a);
ps->a = NULL;
ps->size = 0;
ps->capacity = 0;
}
}
主函数:
#include "Contacts.h"
enum Choice{ Add = 1, Delt, Find, Modify, Display, Empty, Sort, Exit = 0 };
int main()
{
Contacts contacts;
ContactsInit(&contacts);
LoadContacts(&contacts);
int choice_1, choice_2, choice_3;
do
{
menu1();
printf("请输入你的选项:");
scanf("%d", &choice_1);
system("cls");
if (choice_1 != 1 && choice_1 != 0)
{
printf("输入错误,请重新输入!!!\n");
continue;
}
else if (choice_1 == 0)
{
return 0;
}
do
{
menu2();
printf("请输入你的选项:");
scanf("%d", &choice_2);
system("cls");
if (choice_2 < 0 || choice_2 > 7)
{
printf("输入错误,请重新输入!!!\n");
continue;
}
switch (choice_2)
{
case Add:
ContactsAdd(&contacts);
printf("添加成功!\n");
break;
case Delt:
ContactsDelt(&contacts);
printf("删除成功!\n");
break;
case Find:
menu3();
printf("请输入你的选项:");
scanf("%d", &choice_3);
system("cls");
FIND(contacts, choice_3);
break;
case Modify:
menu3();
printf("请输入你的选项:");
scanf("%d", &choice_3);
system("cls");
FIND(contacts, choice_3);
printf("请输入要修改的联系人所对应的下标:");
scanf("%d", &choice_3);
ContactsModify(&contacts, choice_3);
printf("修改成功!");
break;
case Display:
ContactsPrint(contacts);
break;
case Empty:
ContactsDestroy(&contacts);
printf("清空成功!");
break;
case Sort:
menu4();
printf("请输入你的选项:");
scanf("%d", &choice_3);
choice_1 = 0;
ContactsSort(&contacts, choice_3);
printf("排序成功!\n");
break;
case Exit:
SaveContact(&contacts);
ContactsDestroy(&contacts);
break;
}
} while (choice_2);
} while (choice_1);
return 0;
}