整体思路
生活中使用的通讯录一般的功能有:联系人的姓名,电话号码,家庭住址,这里我们就要实现这几个功能,我们还可以添加一些如联系人年龄,清空通讯录,按姓氏排列联系人的功能。
![](https://i-blog.csdnimg.cn/blog_migrate/7e9dd73703fe6b1a4de74eda15af97a7.png)
由于实现通讯录功能需要较多的函数,以及较多的变量,所以我们可以分别建立源项目。
contact.h定义了所有宏常量,定义了主要的结构体,声明主要函数。使得之后再看代码时有一个较为清晰的概念。
contact.c是根据contact.h的声明具体写出了实现通讯录功能所需要的函数
test.c是用来测试通讯录功能的,只要搭建一个合理的框架来合理地使用contact.c中的函数,就可以实现通讯录的功能。
接下来看看每个函数的具体实现
通讯录作主体的定义
通讯录有许多联系人,而每个联系人又有姓名,年龄,电话号码等各种信息,所以用struct定义一个联系人person类,每个联系人的具体信息就是这个类的成员变量。
而通讯录中又有许多的联系人,这最好用一个数组来储存,同时再使用一个变量来记录通讯录中联系人的数量以方便后续操作。所以用struct定义一个通讯录Contact类型,存放所有联系人的数组以及联系人数量就是这个结构体的成员变量。
contact.h
#define MAX_name 20
#define MAX_tele 20
#define MAX_addr 30
#define MAX 100
typedef struct person//每个联系人的信息
{
char name[MAX_name];//联系人姓名
int age;//联系人年龄
int tele[MAX_tele];//联系人号码
char addr[MAX_addr];//联系人住址
}person;//将struct person类型重命名为person方便写入
typedef struct Contact//定义了通讯录中所包含的信息
{
person data[MAX];//结构体数组用来存放每个联系人的信息
int sz;//联系人数量
}Contact,*pcContact;//将struct Contact类型重命名为Contact,指针命名为pcContact
在用户操作前,首先先将通讯录初始化,所有数据都设为0
注意在函数内部操作结构体的所有动作,都必须通过指针
void InitContact(Contact* pc)//和结构体有关的函数传参时一定要传结构体指针,这样速度快效率高
{
pc->sz = 0;
memset(pc->data, 0, sizeof(pc->data));
}
添加联系人
void addmember(Contact* pc)//添加新成员
{
if (pc->sz == MAX)
{
printf("通讯录成员已满,无法再添加新成员\n");
}
printf("请输入名字\n");
scanf("%s", pc->data[pc->sz].name);
printf("请输入年龄\n");
scanf("%d", &(pc->data[pc->sz].age));
printf("请输入电话号码\n");
scanf("%s", pc->data[pc->sz].tele);
printf("请输入地址\n");
scanf("%s", pc->data[pc->sz].addr);
pc->sz++;
printf("添加成功\n");
DisplayContact(pc);
}
在对通讯录操作后,应该让用户再看一下通讯录,以确保他们的修改,这里写一个打印通讯录所有联系人的函数
void DisplayContact(Contact* pc)//进行操作后向用户展示更新后的通讯录
{
char name[] = "姓名";
char age[] = "年龄";
char tele[] = "电话";
char addr[] = "地址";
printf("%20s%20s%20s%20s\n", name, age, tele, addr);
for (int i = 0; i < pc->sz; i++)
{
printf("%20s", pc->data[i].name);
printf("%20d", pc->data[i].age);
printf("%20s", pc->data[i].tele);
printf("%20s", pc->data[i].addr);
printf("\n");
}
printf("\n");
}
删除联系人
void delmember(Contact* pc)
{
if (pc->sz == 0)
{
printf("当前通讯录无成员,无法删除\n");
return;
}
printf("请输入想删除的成员名字\n");//通过名字来查找要删除的联系人
int pos=Find_by_name(pc);//将查找结果返回给pos,找到返回联系人数组下标,找不到返回-1
if (pos != -1)//如果找到
{
for (pos; pos < pc->sz; pos++)
{
pc->data[pos] = pc->data[pos + 1];//由于是数组,不能删除,只能覆盖,将要删除的位置后面的数据向前覆盖一位
}
pc->sz--;//联系人数量-1
DisplayContact(pc);
return;
}
else
{
printf("要删除的成员不存在\n");
DisplayContact(pc);
}
}
按名字寻找联系人的函数
上面函数中int pos=Find_by_name(pc); 是将按名字寻找结果返回给pos变量,由于按名字寻找的功能对于通讯录来说十分重要,所以这里直接抽离出一个函数来实现,而不用每次都在需要用的时候临时写
int Find_by_name(Contact* pc)//通过输入成员名字来查找成员,找到返回成员在data数组中的下标,找不到返回-1
{
char name[MAX_name] = { 0 };
scanf("%s", name);//输入一个姓名
int pos = 0;
for (int i = 0; i < pc->sz; i++)//将这个姓名在联系人中遍历寻找
{
if (strcmp(name, pc->data[i].name) == 0)//找到返回下标
{
pos = i;
return pos;
break;
}
}
return -1;//找不返回-1
}
寻找联系人
void searchmember(Contact* pc)
{
printf("请输入你想寻找的成员的名字\n");
int pos=Find_by_name(pc);
if (pos != -1)
{
char name[] = "姓名";
char age[] = "年龄";
char tele[] = "电话";
char addr[] = "地址";
printf("%20s%20s%20s%20s\n", name, age, tele, addr);
printf("%20s", pc->data[pos].name);
printf("%20d", pc->data[pos].age);
printf("%20s", pc->data[pos].tele);
printf("%20s", pc->data[pos].addr);
printf("\n");
printf("\n");
}
else
{
printf("未找到该成员\n");
printf("\n");
}
}
修改联系人
void modifymember(Contact* pc)
{
if (pc->sz == 0)
{
printf("当前通讯录无成员,无法修改\n");
return;
}
printf("请输入你想修改的成员的名字\n");
int pos=Find_by_name(pc);
if (pos != -1)
{
printf("请重新输入名字\n");
scanf("%s", pc->data[pos].name);
printf("请重新输入年龄\n");
scanf("%d", &(pc->data[pos].age));
printf("请重新输入电话号码\n");
scanf("%s", pc->data[pos].tele);
printf("请重新输入地址\n");
scanf("%s", pc->data[pos].addr);
DisplayContact(pc);
return;
}
printf("未找到要修改的成员\n");
printf("\n");
}
清空通讯录
void resetContact(Contact* pc)
{
printf("确认要清空所有联系人吗?\n");
printf("请输入:1.我再想想 2.确认\n");
int confirm = 0;
scanf("%d", &confirm);
if (2 == confirm)
{
memset(pc, 0, sizeof(pc->data));//相当于又初始化了一次
}
else
return;
}
按姓氏给联系人排序
使用快速排序qsort函数,还需要自己写一个比较函数(cmp_by_name)
快速排序的相关知识
int cmp_by_name(const void* p1, const void* p2)
{
return strcmp(((person*)p1)->name, ((person*)p2)->name);
}
void sortmember_name(Contact* pc)
{
if (pc->sz < 2)
{
printf("当前通讯录成员无法排序\n");
printf("\n");
return;
}
qsort(pc->data, pc->sz, sizeof(pc->data[0]), cmp_by_name);
DisplayContact(pc);
printf("\n");
}
最后看一下test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include"contact.h"
enum option
{
exit,//0
add,//1
del,//2
search,//3
modify,//4
show,//5
reset,//6
sort//7
};
int main()
{
int input = 0;
Contact con;
InitContact(&con);
do
{
menu();
printf("您想执行的操作\n");
scanf("%d", &input);
switch (input)
{
case add://用枚举定义常量可以让程序的可读性增加
addmember(&con);
break;
case del:
delmember(&con);
break;
case search:
searchmember(&con);
break;
case modify:
modifymember(&con);
break;
case show:
DisplayContact(&con);
break;
case reset:
resetContact(&con);
break;
case sort:
sortmember_name(&con);
break;
case exit:
break;
default:
printf("请输入正确的操作数\n");
break;
}
} while (input);
return 0;
}