通讯录的主要功能:
- 增加联系人
- 删除联系人
- 查找联系人
- 排序联系人
- 修改联系人
- 显示所有联系人
- 清空所有联系人
- 退出
接下来让我们来看看怎么实现的吧!
1、初始化通讯录 1.1定义结构体联系人的信息应该包括 姓名、性别、电话、地址,这是多个类型复合在一起,因此我们应该用一个结构体来定义联系人(typedef只是把struct perinfo 重命名成perinfo,让名字更简单好记一点)
typedef struct perinfo
{
char name[20];//姓名
char sex[3];
char number[12];//电话
char address[20];//地址
}perinfo;
为了方便修改以上数组的容量,我们定义几个符号常量
#define name_max 20
#define number_max 12
#define address_max 20
#define sex_max 3
typedef struct perinfo
{
char name[name_max];//姓名
//char sex;//女为f,男为m
char sex[sex_max];
char number[number_max];//电话
char address[address_max];//地址
}perinfo;
通讯录中不仅有联系人的信息,也应该有通讯录的人数,所以我们再用一个结构体存放联系人的信息和联系人的个数。
typedef struct contact
{
perinfo member[1000];
int sz;//记录当前通讯录中已有的人数
}contact;
为了方便修改通讯录可以存放人数的容量,我们定义一个负号常量
#define Max 1000
typedef struct contact
{
perinfo member[Max];
int sz;//记录当前通讯录中已有的人数
}contact;
1.2 初始化结构体
初始化结构体的目的:把member数组里的内容初始化为0,sz置为0
//初始化结构体
void Initcontact(contact* pcaller)
{
assert(pcaller); //防止pcaller为NULL指针
pcaller->sz = 0;
memset(pcaller, 0, sizeof(pcaller->member)); //按字节改变
}
2、通讯录主要功能的实现
2.1 增加联系人
//添加联系人
void Addcontact(contact* pcaller)
{
if (pcaller->sz == Max)
{
printf("通讯录已满,添加失败!n");
return;
}
printf("请输入您所添加联系人的姓名:");
scanf("%s", pcaller->member[pcaller->sz].name); //member[ pcaller->sz ]注意括号里所写的
printf("请输入您所添加联系人的性别:");
scanf("%s", pcaller->member[pcaller->sz].sex);
printf("请输入您所添加联系人的电话:");
scanf("%s", pcaller->member[pcaller->sz].number);
printf("请输入您所添加联系人的住址:");
scanf("%s", pcaller->member[pcaller->sz].address);
pcaller->sz++;
printf("添加成功n");
}
2.2 打印联系人
打印通讯录中所有人的信息
//打印联系人
void Printcontact(contact* pcaller)
{
int i;
printf("%-10s %-6s %-12s %-20sn", "姓名", "性别", "手机号", "住址");
for (i = 0; i < (pcaller->sz); i++)
{
printf("%-10s %-6s %-12s %-20sn", pcaller->member[i].name, pcaller->member[i].sex, pcaller->member[i].number, pcaller->member[i].address);
//%10s 是右对齐,%-10s 是左对齐
}
printf("目前有 %d 个联系人n", pcaller->sz);
}
2.3 删除联系人
//删除指定联系人
void Delcontact(contact* pcaller, char *name)
{
assert(pcaller&&name);
for (int i = 0; i < pcaller->sz; i++)
{
if (strcmp(pcaller->member[i].name, name) == 0) //字符串与字符串的比较需要用strcmp
{
for (int j = i; j < pcaller->sz - 1; j++)
{
pcaller->member[j] = pcaller->member[j + 1];
//memmove(&(pcaller->member[j]), &(pcaller->member[j + 1]), sizeof(pcaller->member[j]));
(pcaller->sz)--; //此时通讯录里面的人数减少了一个
printf("删除成功!!n");
}
}
Printcontact(pcaller);
return;
}
printf("查无此人n");
}
删除指定联系人的原理就是,把该联系人的信息用后一个联系人的信息覆盖住,从该联该系人后一个联系人开始,全部往前挪一个位置。
至于如何覆盖,有两种方式
- 直接赋值 member[j]=member[j+1];
- 用memmove函数 memmove(&(pcaller->member[j]), &(pcaller->member[j + 1]), sizeof(pcaller->member[j]));
根据输入的联系人的姓名来找到联系人的信息并打印出来。
//查找联系人
void Searchcontact(contact* pcaller, char *name)
{
assert(pcaller&&name);
for (int i = 0; i < pcaller->sz; i++)
{
if (strcmp(pcaller->member[i].name, name) == 0)
{
printf("%-10s %-6s %-12s %-20sn", "姓名", "性别", "手机号", "住址");
printf("%-10s %-6s %-12s %-20sn", pcaller->member[i].name, pcaller->member[i].sex, pcaller->member[i].number, pcaller->member[i].address);
}
return;
}
printf("查无此人n");
}
2.5 修改联系人
//修改联系人
void Modifycontact(contact* pcaller, char* name)
{
assert(pcaller&&name);
for (int i = 0; i < pcaller->sz; i++)
{
if (strcmp(pcaller->member[i].name, name) == 0)
{
printf("请输入您所修改联系人的姓名:");
scanf("%s", pcaller->member[i].name);
printf("请输入您所修改联系人的性别:");
scanf("%s", pcaller->member[i].sex);
printf("请输入您所修改联系人的电话:");
scanf("%s", pcaller->member[i].number);
printf("请输入您所修改联系人的住址:");
scanf("%s", pcaller->member[i].address);
printf("修改成功n");
}
return;
}
printf("查无此人n");
}
2.6 排序联系人
根据姓名排序联系人,我们可以用qsort函数实现快排,为了使用qsort函数我们还要写一个比较函数。
//排序联系人(按姓名排序)
int compare_name(const perinfo* e1, const perinfo* e2)
{
return strcmp(e1->name, e2->name);
}
void Sortcontact(contact* pcaller)
{
qsort(pcaller->member, pcaller->sz, sizeof(pcaller->member[0]), compare_name);
Printcontact(pcaller);
}
2.7 清空所有联系人
清空所有联系人,也就是相当于给通讯录重新初始化一次
//清空所有联系人
void Empty_contact(contact*pcaller)
{
Initcontact(pcaller);
printf("清空成功n");
}
3.一些小细节上的处理
enum select
{
exit0,
add,
del,
search,
print,
modify,
sort,
empty
};
void menu()
{
int op = 0;
contact caller;
//初始化结构体
Initcontact(&caller);
do
{
printf("******** 欢迎使用通讯录 ********************n");
printf("****1、增加联系人*******2、删除联系人*********n");
printf("****3、查找联系人*******4、显示所有联系人****n");
printf("****5、修改联系人*******6、排序联系人********n");
printf("****7、清空所有联系人**0、退出*************n");
printf("***************************************************n");
printf("请输入你的选择:>");
scanf("%d", &op);
switch (op)
{
case add:
Addcontact(&caller);
break;
case del:
printf("请输入你想删除的联系人的姓名:");
char name[20];
scanf("%s", name);
Delcontact(&caller, name);
break;
case search:
printf("请输入你想查找的联系人的姓名:");
char name1[20];
scanf("%s", name1);
Searchcontact(&caller, name1);
break;
case print:
Printcontact(&caller);
break;
case modify:
printf("请输入你想删除的联系人的姓名:");
char name2[20];
scanf("%s", name2);
Modifycontact(&caller, name2);
break;
case sort:
Sortcontact(&caller);
break;
case empty:
Empty_contact(&caller);
case exit0:
printf("您已退出!");
break;
default:
printf("输入错误,请重新输入");
}
} while (op);
}
在menu函数中我们使用了枚举常量,为什么要这样呢?
- 枚举常量本身没有实际意义,但是能提高我们的可读性,其名字可以很好的体现要实现什么功能。
- 系统会为枚举常量赋予初值,我们可以利用这个代替op
我们将代码分到三个文件中,一个工程是需要由一个头文件,两个源文件组成的。
Contact.h 为头文件,用于放结构体的声明,符号常量的定义,函数的声明。
#pragma once #include#include #include #include #define Max 1000 #define name_max 20 #define number_max 12 #define address_max 20 #define sex_max 3 enum select { exit0, add, del, search, print, modify, sort, empty }; typedef struct perinfo { char name[name_max];//姓名 //char sex;//女为f,男为m char sex[sex_max]; char number[number_max];//电话 char address[address_max];//地址 }perinfo; typedef struct contact { perinfo member[Max]; int sz;//记录当前通讯录中已有的人数 }contact; void Initcontact(contact* pcaller); void Addcontact(contact* pcaller); void Printcontact(contact* pcaller); void Delcontact(contact* pcaller, char* name); void Searchcontact(contact* pcaller, char* name); void Modifycontact(contact* pcaller, char* name); void Sortcontact(contact* pcaller); void Empty_contact(contact*pcaller);
Contact.c为源文件,存放函数实现的代码,封装函数。连接Contact.c和Contact.h只需要用#include“Contact.h”就可以了;
注意:自己写的头文件用 “ ” 引用。
#include"contact.h"
//初始化结构体
void Initcontact(contact* pcaller)
{
assert(pcaller);
pcaller->sz = 0;
memset(pcaller, 0, sizeof(pcaller->member));
}
//添加联系人
void Addcontact(contact* pcaller)
{
if (pcaller->sz == Max)
{
printf("通讯录已满,添加失败!n");
return;
}
printf("请输入您所添加联系人的姓名:");
scanf("%s", pcaller->member[pcaller->sz].name); //member[ pcaller->sz ]注意括号里所写的
//char c;
//while (c = getchar() != 'n')
//{
//} //由于性别我们只定义了一个字符,在之前我们输入联系人姓名时,会按下回车键,如果不用循环把'n'去掉,就会把'n'给sex
printf("请输入您所添加联系人的性别:");
//scanf("%c", &(pcaller->member[pcaller->sz].sex));
scanf("%s", pcaller->member[pcaller->sz].sex);
printf("请输入您所添加联系人的电话:");
scanf("%s", pcaller->member[pcaller->sz].number);
printf("请输入您所添加联系人的住址:");
scanf("%s", pcaller->member[pcaller->sz].address);
pcaller->sz++;
printf("添加成功n");
}
//打印联系人
void Printcontact(contact* pcaller)
{
int i;
printf("%-10s %-6s %-12s %-20sn", "姓名", "性别", "手机号", "住址");
for (i = 0; i < (pcaller->sz); i++)
{
printf("%-10s %-6s %-12s %-20sn", pcaller->member[i].name, pcaller->member[i].sex, pcaller->member[i].number, pcaller->member[i].address);
}
printf("目前有 %d 个联系人n", pcaller->sz);
}
//删除联系人
void Delcontact(contact* pcaller, char *name)
{
assert(pcaller&&name);
for (int i = 0; i < pcaller->sz; i++)
{
if (strcmp(pcaller->member[i].name, name) == 0)
{
for (int j = i; j < pcaller->sz - 1; j++)
{
pcaller->member[j] = pcaller->member[j + 1];
//memmove(&(pcaller->member[j]), &(pcaller->member[j + 1]), sizeof(pcaller->member[j]));
(pcaller->sz)--;
printf("删除成功!!n");
}
}
Printcontact(pcaller);
return;
}
printf("查无此人n");
}
//查找联系人
void Searchcontact(contact* pcaller, char *name)
{
assert(pcaller&&name);
for (int i = 0; i < pcaller->sz; i++)
{
if (strcmp(pcaller->member[i].name, name) == 0)
{
printf("%-10s %-6s %-12s %-20sn", "姓名", "性别", "手机号", "住址");
printf("%-10s %-6s %-12s %-20sn", pcaller->member[i].name, pcaller->member[i].sex, pcaller->member[i].number, pcaller->member[i].address);
}
return;
}
printf("查无此人n");
}
//修改联系人
void Modifycontact(contact* pcaller, char* name)
{
assert(pcaller&&name);
for (int i = 0; i < pcaller->sz; i++)
{
if (strcmp(pcaller->member[i].name, name) == 0)
{
printf("请输入您所修改联系人的姓名:");
scanf("%s", pcaller->member[i].name);
printf("请输入您所修改联系人的性别:");
scanf("%s", pcaller->member[i].sex);
printf("请输入您所修改联系人的电话:");
scanf("%s", pcaller->member[i].number);
printf("请输入您所修改联系人的住址:");
scanf("%s", pcaller->member[i].address);
printf("修改成功n");
}
return;
}
printf("查无此人n");
}
//排序联系人
int compare_name(const perinfo* e1, const perinfo* e2)
{
return strcmp(e1->name, e2->name);
}
void Sortcontact(contact* pcaller)
{
qsort(pcaller->member, pcaller->sz, sizeof(pcaller->member[0]), compare_name);
Printcontact(pcaller);
}
//清空所有联系人
void Empty_contact(contact*pcaller)
{
Initcontact(pcaller);
printf("清空成功n");
}
test.c 为源文件,用于测试通讯录的功能
#include"contact.h"
void menu()
{
int op = 0;
contact caller;
//初始化结构体
Initcontact(&caller);
do
{
printf("******** 欢迎使用通讯录 ********************n");
printf("****1、增加联系人*******2、删除联系人*********n");
printf("****3、查找联系人*******4、显示所有联系人****n");
printf("****5、修改联系人*******6、排序联系人********n");
printf("****7、清空所有联系人**0、退出*************n");
printf("***************************************************n");
printf("请输入你的选择:>");
scanf("%d", &op);
switch (op)
{
case add:
Addcontact(&caller);
break;
case del:
printf("请输入你想删除的联系人的姓名:");
char name[20];
scanf("%s", name);
Delcontact(&caller, name);
break;
case search:
printf("请输入你想查找的联系人的姓名:");
char name1[20];
scanf("%s", name1);
Searchcontact(&caller, name1);
break;
case print:
Printcontact(&caller);
break;
case modify:
printf("请输入你想删除的联系人的姓名:");
char name2[20];
scanf("%s", name2);
Modifycontact(&caller, name2);
break;
case sort:
Sortcontact(&caller);
break;
case empty:
Empty_contact(&caller);
case exit0:
printf("您已退出!");
break;
default:
printf("输入错误,请重新输入");
}
} while (op);
}
int main()
{
menu();
return 0;
}
写了一个通讯录的代码并不只是一个通讯录的代码,平时学校要求做的C语言或者C++的课题,项目,大作业,如:图书管理系统,诊所管理系统等等。这些都是差不多的实现方式,学会通讯录就可以解锁其它大同小异的问题。
通讯录就这样写完了,后面我还会介绍动态增长版本的通讯录以及用文件操作通讯录,bye~



