目录
一、通讯录功能实现的详细描述
二、通讯录的代码及思路实现
2、1 定义联系人结构体
2、2 初始化就结构体与释放动态开辟空间的实现
2、3 菜单打印
2、4 添加联系人信息
2、5 删除联系人信息
2、6 查询联系人信息
2、7 修改联系人信息
2、8 打印所有联系人信息
2、9 排序整理联系人信息
2、10 删除所有联系人信息
三、通讯录代码的整合
contact.h
contact.c
test.c
四、总结
标题:通讯录思路及代码实现详解
作者:@Ggggggtm
寄语:与其忙着诉苦,不如低头赶路,奋路前行,终将遇到一番好风景
我们前面详细讲述了动态内存管理详解(malloc、calloc、realloc)和结构体的声明使用及存储方式,那么这篇文章我们来一个综合用到结构体和动态内存开辟练习。实现一个通讯录,该通讯录的功能有增删查改、排序、查看操作。
一、通讯录功能实现的详细描述
在日常生活中,通讯录是我们每个人都非常熟悉的了。最常见的就是手机中的电话薄。我们就根据手机中的电话薄的功能来模拟实现一个通讯录。我们先看实现的通讯录都有哪些具体细节:
- 打印一个菜单,提供用户选择功能;
- 添加联系人信息;
- 删除联系人信息;
- 查询联系人信息;
- 修改联系人信息;
- 显示所有联系人信息;
- 对所有联系人信息进行排序整理;
- 删除所有联系人信息;
- 操作完毕可选择退出。
以上就是实现的通讯录的整体细节与模板,具体每个功能的具体实现思路及细节我们接着往下看,我会给大家一一实现与讲解。
二、通讯录的代码及思路实现
2、1 定义联系人结构体
在整体实现之前,我们需要先把联系人结构体实现出来。我们这个结构体需要包含联系人的所有信息。同时,我们为了动态实现通讯录,我们需要再定义一个结构体,包含一个联系人结构体指针、记录存储的多少个联系人的一个变量和一个记录联系人结构体的容量。我们具体看代码实现。
#define MAX_NAME 20
#define MAX_ADDR 20
#define MAX_TELE 12
#define MAX_SEX 5
#define INIT_SZ 50
#define INCREASE_SZ 20
typedef struct PeoInfo
{
char name[MAX_NAME];
int age;
char sex[MAX_SEX];
char addr[MAX_ADDR];
char tele[MAX_TELE];
}PeoInfo;
typedef struct Contact
{
PeoInfo* data;
int size;
int capacity;
}Contact;
2、2 初始化就结构体与释放动态开辟空间的实现
在这里我们把初始化就结构体与释放动态开辟空间的实现放到一块实现,因为他们本身就可以看做一对。在初始化结构体时,我们需要初始给出通讯录可存储多少个联系人,还要给出增长空间的大小。我们来看代码:
void InitContact(Contact* ps)
{
PeoInfo* str = (PeoInfo*)calloc(INIT_SZ, sizeof(PeoInfo));
if (str == NULL)
{
perror("InitContact::calloc");
return;
}
ps->data = str;
ps->size = 0;
ps->capacity = INIT_SZ;
}
void DestoryContact(Contact* ps)
{
free(ps->data);
ps->capacity = 0;
ps->size = 0;
ps->data = NULL;
ps = NULL;
}
2、3 菜单打印
菜单的打印是我们必须第一个实现的,也是我们实现整个通讯录的参照。 菜单的打印需要简单明了即可。且实现比较简单。注意要单独放在一个自定义函数中,让主函数中的代码尽量减少,方便观察。
void menu()
{
printf("********************************\n");
printf("**** 1.Add 2.Del ****\n");
printf("**** 3.Reserch 4.Modify ****\n");
printf("**** 5.Show 6.Sort ****\n");
printf("**** 7.DelAll 0.Exit ****\n");
printf("********************************\n");
}
2、4 添加联系人信息
再添加联系人之前,我们要先判断通讯录是否为满。如果满了的话我们需要进行扩容,再进行添加联系人。注意,为了输出格式简介,我们这里在添加联系人时就进行了格式化添加。具体我们结合这代码一起理解一下。
void check_capacity(Contact* ps)
{
if (ps->capacity == ps->size)
{
PeoInfo* str = (PeoInfo*)realloc(ps->data, sizeof(PeoInfo) * (ps->capacity + INCREASE_SZ));
if (str == NULL)
{
perror("check_capacity::realloc");
return;
}
ps->data = str;
ps->capacity += INCREASE_SZ;
printf("增容成功\n");
}
}
void AddContact(Contact* ps)
{
check_capacity(ps);
printf("请输入要添加的姓名:");
scanf("%s", ps->data[ps->size].name);
printf("请输入要添加的年龄:");
scanf("%d", &ps->data[ps->size].age);
printf("请输入要添加的性别:");
scanf("%s", ps->data[ps->size].sex);
printf("请输入要添加的地址:");
scanf("%s", ps->data[ps->size].addr);
printf("请输入要添加的电话:");
scanf("%s", ps->data[ps->size].tele);
ps->size++;
}
2、5 删除联系人信息
我们这里是根据用户所输入的联系人姓名进行删除的,所以我们先要判断用户所输入的联系人是否存在。当然,如果通讯录为空的话,我们就直接可以知道删除失败的。由于后面多个功能都需要查找联系人,所以我们这里把查找联系人独立分装成一个函数,以便我们后续的使用。
int find(Contact* ps, char* name)
{
for (int i = 0; i < ps->size; i++)
{
if (strcmp(ps->data[i].name, name) == 0)
{
return i;
}
}
return -1;
}
void DelContact(Contact* ps)
{
if (ps->size == 0)
{
printf("通讯录为空,删除失败\n");
return;
}
char name[MAX_NAME];
printf("请输入要删除人的姓名:");
scanf("%s", name);
int ret = find(ps, name);
if (ret == -1)
{
printf("索要删除的人不存在哦\n");
return;
}
int i = 0;
for (i = ret; i < ps->size - 1; i++)
{
ps->data[i] = ps->data[i + 1];
}
ps->size--;
printf("删除成功\n");
}
2、6 查询联系人信息
我们这里的查询寻联系人与find()函数并不相同,但是又有联系。我们需要查找出联系人,如果该联系人存在,我们就输出该联系人的信息,注意输出格式简洁。如果不存在,我们就提示用户该联系人不存在。代码的实现也相对简单,我们直接看代码的实现:
void ReserchContact(Contact* ps)
{
char name[MAX_NAME];
printf("请输入要查询人的姓名:");
scanf("%s", name);
int ret = find(ps, name);
if (ret == -1)
{
printf("通讯录中没有%s的信息哦\n", name);
return;
}
printf("%-20s%-20s%-15s%-20s%-12s\n", "姓名", "年龄", "性别", "地址", "电话");
printf("%-20s%-20d%-15s%-20s%-12s\n", ps->data[ret].name, ps->data[ret].age, ps->data[ret].sex, ps->data[ret].addr, ps->data[ret].tele);
}
2、7 修改联系人信息
修改联系人信息与查询联系人信息思路大同小异,代码实现也是相似。修改联系人信息我们先要找到联系人,然后再提示用户输入修改联系人的信息。我们直接看代码:
void ModifyContact(Contact* ps)
{
char name[MAX_NAME];
printf("请输入要修改人的姓名:");
scanf("%s", name);
int ret = find(ps, name);
if (ret == -1)
{
printf("通讯录中没有%s的信息哦\n", name);
return;
}
printf("请输入姓名:");
scanf("%s", ps->data[ret].name);
printf("请输入年龄:");
scanf("%d", &ps->data[ret].age);
printf("请输入性别:");
scanf("%s", ps->data[ret].sex);
printf("请输入地址:");
scanf("%s", ps->data[ret].addr);
printf("请输入电话:");
scanf("%s", ps->data[ret].tele);
printf("修改成功\n");
}
2、8 打印所有联系人信息
我们只需判断通讯录是否为空,如果为空就提示用户。不为空我们就直接遍历打印即可。实现相对较为简单,我们直接看代码:
void ShowContact(Contact* ps)
{
printf("%-20s%-20s%-15s%-20s%-12s\n", "姓名", "年龄", "性别", "地址", "电话");
int i = 0;
for (i = 0; i < ps->size; i++)
{
printf("%-20s%-20d%-15s%-20s%-12s\n", ps->data[i].name, ps->data[i].age, ps->data[i].sex, ps->data[i].addr, ps->data[i].tele);
}
}
2、9 排序整理联系人信息
我们先首先要给出一个排序菜单,提供给客户选择根据联系人的哪项信息来进行排序,我们这里利用qsort函数实现按排序。整体还是简单的。我们看代码实现:
void SortMenu()
{
printf("\n");
printf("********************************\n");
printf("**** 1.name 2.age ****\n");
printf("**** 3.addr 4.tele ****\n");
printf("**** 5.sex ****\n");
printf("********************************\n");
printf("\n");
}
int cmp_by_name(const void* e1, const void* e2)
{
return strcmp((*((PeoInfo*)e1)).name, (*((PeoInfo*)e2)).name);
}
int cmp_by_age(const void* e1, const void* e2)
{
return (*((PeoInfo*)e1)).age - (*((PeoInfo*)e2)).age;
}
int cmp_by_addr(const void* e1, const void* e2)
{
return strcmp((*((PeoInfo*)e1)).addr, (*((PeoInfo*)e2)).addr);
}
int cmp_by_tele(const void* e1, const void* e2)
{
return strcmp((*((PeoInfo*)e1)).tele, (*((PeoInfo*)e2)).tele);
}
int cmp_by_sex(const void* e1, const void* e2)
{
return strcmp((*((PeoInfo*)e1)).sex, (*((PeoInfo*)e2)).sex);
}
void SortContact(Contact* ps)
{
int input = 0;
if (ps->size == 0)
{
printf("通讯录为空,不用排序哦\n");
}
do
{
SortMenu();
printf("请选择要根据什么排序:");
scanf("%d", &input);
switch (input)
{
case 1:
qsort(ps->data, ps->size, sizeof(ps->data[0]), cmp_by_name);
break;
case 2:
qsort(ps->data, ps->size, sizeof(ps->data[0]), cmp_by_age);
break;
case 3:
qsort(ps->data, ps->size, sizeof(ps->data[0]), cmp_by_addr);
break;
case 4:
qsort(ps->data, ps->size, sizeof(ps->data[0]), cmp_by_tele);
break;
case 5:
qsort(ps->data, ps->size, sizeof(ps->data[0]), cmp_by_sex);
break;
default:
printf("输入有误,请重新输入:");
}
} while (0);
}
2、10 删除所有联系人信息
这个是最简单了,我们只需要先判断通讯录是否为空,不为空我们直接把size置0即可。
void DelAllContact(Contact* ps)
{
if (ps->size == 0)
{
printf("通讯录已经为空了哦\n");
return;
}
ps->size = 0;
printf("删除成功\n");
}
三、通讯录代码的整合
由于代码量相对来说有一点多,所以我们就将函数的声明的定义分开,这样有利于提高代码的可读性,同时会保持一个良好的思路,且方便编写代码。
我们将函数的声明放在单独的一个contact.h的头文件,函数的实现放在一个单独的contact.c源文件,函数的主方法及调用放在另一个单独的test.c源文件。
contact.h
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<assert.h>
#include<string.h>
#include<stdlib.h>
#define MAX 100
#define MAX_NAME 20
#define MAX_ADDR 20
#define MAX_TELE 12
#define MAX_SEX 5
#define INIT_SZ 2
#define INCREASE_SZ 1
typedef struct PeoInfo
{
char name[MAX_NAME];
int age;
char sex[MAX_SEX];
char addr[MAX_ADDR];
char tele[MAX_TELE];
}PeoInfo;
typedef struct Contact
{
PeoInfo* data;
int size;
int capacity;
}Contact;
//初始化
void InitContact(Contact* ps);
//释放动态开辟空间
void DestoryContact(Contact* ps);
//菜单
void menu();
//添加个人信息
void AddContact(Contact* ps);
//删除个人信息
void DelContact(Contact* s);
//查询个人信息
void ReserchContact(Contact* s);
//修改个人信息
void ModifyContact(Contact* s);
//查看整个通讯录
void ShowContact(Contact* s);
//对通讯录进行排序
void SortContact(Contact* s);
//排序菜单
void SortMenu();
//删除整个通讯录信息
void DelAllContact(Contact* s);
contact.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"Contact.h"
void InitContact(Contact* ps)
{
PeoInfo* str = (PeoInfo*)calloc(INIT_SZ, sizeof(PeoInfo));
if (str == NULL)
{
perror("InitContact::calloc");
return;
}
ps->data = str;
ps->size = 0;
ps->capacity = INIT_SZ;
}
void DestoryContact(Contact* ps)
{
free(ps->data);
ps->capacity = 0;
ps->size = 0;
ps->data = NULL;
ps = NULL;
}
void menu()
{
printf("********************************\n");
printf("**** 1.Add 2.Del ****\n");
printf("**** 3.Reserch 4.Modify ****\n");
printf("**** 5.Show 6.Sort ****\n");
printf("**** 7.DelAll 0.Exit ****\n");
printf("********************************\n");
}
int find(Contact* ps, char* name)
{
for (int i = 0; i < ps->size; i++)
{
if (strcmp(ps->data[i].name, name) == 0)
{
return i;
}
}
return -1;
}
void check_capacity(Contact* ps)
{
if (ps->capacity == ps->size)
{
PeoInfo* str = (PeoInfo*)realloc(ps->data, sizeof(PeoInfo) * (ps->capacity + INCREASE_SZ));
if (str == NULL)
{
perror("check_capacity::realloc");
return;
}
ps->data = str;
ps->capacity += INCREASE_SZ;
printf("增容成功\n");
}
}
void AddContact(Contact* ps)
{
check_capacity(ps);
printf("请输入要添加的姓名:");
scanf("%s", ps->data[ps->size].name);
printf("请输入要添加的年龄:");
scanf("%d", &ps->data[ps->size].age);
printf("请输入要添加的性别:");
scanf("%s", ps->data[ps->size].sex);
printf("请输入要添加的地址:");
scanf("%s", ps->data[ps->size].addr);
printf("请输入要添加的电话:");
scanf("%s", ps->data[ps->size].tele);
ps->size++;
}
void DelContact(Contact* ps)
{
if (ps->size == 0)
{
printf("通讯录为空,删除失败\n");
return;
}
char name[MAX_NAME];
printf("请输入要删除人的姓名:");
scanf("%s", name);
int ret = find(ps, name);
if (ret == -1)
{
printf("索要删除的人不存在哦\n");
return;
}
int i = 0;
for (i = ret; i < ps->size - 1; i++)
{
ps->data[i] = ps->data[i + 1];
}
ps->size--;
printf("删除成功\n");
}
void ReserchContact(Contact* ps)
{
char name[MAX_NAME];
printf("请输入要查询人的姓名:");
scanf("%s", name);
int ret = find(ps, name);
if (ret == -1)
{
printf("通讯录中没有%s的信息哦\n", name);
return;
}
printf("%-20s%-20s%-15s%-20s%-12s\n", "姓名", "年龄", "性别", "地址", "电话");
printf("%-20s%-20d%-15s%-20s%-12s\n", ps->data[ret].name, ps->data[ret].age, ps->data[ret].sex, ps->data[ret].addr, ps->data[ret].tele);
}
void ModifyContact(Contact* ps)
{
char name[MAX_NAME];
printf("请输入要修改人的姓名:");
scanf("%s", name);
int ret = find(ps, name);
if (ret == -1)
{
printf("通讯录中没有%s的信息哦\n", name);
return;
}
printf("请输入姓名:");
scanf("%s", ps->data[ret].name);
printf("请输入年龄:");
scanf("%d", &ps->data[ret].age);
printf("请输入性别:");
scanf("%s", ps->data[ret].sex);
printf("请输入地址:");
scanf("%s", ps->data[ret].addr);
printf("请输入电话:");
scanf("%s", ps->data[ret].tele);
printf("修改成功\n");
}
void ShowContact(Contact* ps)
{
printf("%-20s%-20s%-15s%-20s%-12s\n", "姓名", "年龄", "性别", "地址", "电话");
int i = 0;
for (i = 0; i < ps->size; i++)
{
printf("%-20s%-20d%-15s%-20s%-12s\n", ps->data[i].name, ps->data[i].age, ps->data[i].sex, ps->data[i].addr, ps->data[i].tele);
}
}
void SortMenu()
{
printf("\n");
printf("********************************\n");
printf("**** 1.name 2.age ****\n");
printf("**** 3.addr 4.tele ****\n");
printf("**** 5.sex ****\n");
printf("********************************\n");
printf("\n");
}
int cmp_by_name(const void* e1, const void* e2)
{
return strcmp((*((PeoInfo*)e1)).name, (*((PeoInfo*)e2)).name);
}
int cmp_by_age(const void* e1, const void* e2)
{
return (*((PeoInfo*)e1)).age - (*((PeoInfo*)e2)).age;
}
int cmp_by_addr(const void* e1, const void* e2)
{
return strcmp((*((PeoInfo*)e1)).addr, (*((PeoInfo*)e2)).addr);
}
int cmp_by_tele(const void* e1, const void* e2)
{
return strcmp((*((PeoInfo*)e1)).tele, (*((PeoInfo*)e2)).tele);
}
int cmp_by_sex(const void* e1, const void* e2)
{
return strcmp((*((PeoInfo*)e1)).sex, (*((PeoInfo*)e2)).sex);
}
void SortContact(Contact* ps)
{
int input = 0;
if (ps->size == 0)
{
printf("通讯录为空,不用排序哦\n");
}
do
{
SortMenu();
printf("请选择要根据什么排序:");
scanf("%d", &input);
switch (input)
{
case 1:
qsort(ps->data, ps->size, sizeof(ps->data[0]), cmp_by_name);
break;
case 2:
qsort(ps->data, ps->size, sizeof(ps->data[0]), cmp_by_age);
break;
case 3:
qsort(ps->data, ps->size, sizeof(ps->data[0]), cmp_by_addr);
break;
case 4:
qsort(ps->data, ps->size, sizeof(ps->data[0]), cmp_by_tele);
break;
case 5:
qsort(ps->data, ps->size, sizeof(ps->data[0]), cmp_by_sex);
break;
default:
printf("输入有误,请重新输入:");
}
} while (0);
}
void DelAllContact(Contact* ps)
{
if (ps->size == 0)
{
printf("通讯录已经为空了哦\n");
return;
}
ps->size = 0;
printf("删除成功\n");
}
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"Contact.h"
int main()
{
int input = 0;
Contact s;
InitContact(&s);
do
{
menu();
printf("请选择->");
scanf("%d", &input);
switch (input)
{
case 1:
AddContact(&s);
break;
case 2:
DelContact(&s);
break;
case 3:
ReserchContact(&s);
break;
case 4:
ModifyContact(&s);
break;
case 5:
ShowContact(&s);
break;
case 6:
SortContact(&s);
break;
case 7:
DelAllContact(&s);
break;
case 0:
DestoryContact(&s);
printf("退出通讯录\n");
break;
default:
printf("输入有误,请重新输入:");
}
} while (input);
return 0;
}
四、总结
我们要实现通讯录前,我们应该有一个整体的模板和思路,这样对于我们后续的实现比较有利。整个实现的过程相对来说并不是很难,中间在添加联系人和删除联系人的时候有几个细节是需要我们注意的。当我们有了整体思路,实现起来也就不是问题了。
对通讯录的实现就到这里,希望本篇文章会对你有所帮助,感谢阅读ovo~