本次通讯录的实现主要涉及的知识点是:结构体,枚举,函数设计等知识点,其中结构体和枚举是本次的主要知识点,可以这么说本章节是对前两期博客的一个知识总结( C语言结构体讲解和 枚举类型的使用),也可以说是将知识运用到实际生活当中,好了长话短说,我们进入今天的主题。
在实现一个通讯录的时候,我们都要先构思出它的框架,它的成员信息有什么,以及这个通讯录要实现的功能是什么,等等。我们知道一个人的基本信息包括:名字,年龄,性别,电话,住址。而这个通讯录的基本功能包括:1.成员的增加,2.成员的展示,3.成员的查找,4.成员的修改,5.成员的删除,6.成员的排序。现在我们来一步一步实现。
我们要设计出一个通讯录,这个通讯录是给用户使用的,那既然是给用户使用的你总得让用户知道你设计出来的通讯录有什么功能把,所以设计出一个菜单,菜单里面包含了全部的功能是比较关键的一步的。
代码如下:
void menu()
{
printf("**************** Menu *****************\n");
printf("***** 1.add 2.show *****\n");
printf("***** 3.search 4.modify *****\n");
printf("***** 5.del 6.sort *****\n");
printf("***** 0.exit *****\n");
printf("***************************************\n");
}
我们有了菜单就要实现这些菜单上的功能,而实现这些功能的时候就是输入菜单上功能前面的数子,那我们就会想到用switch语句加上do while语句,来进行功能的选择。但是我们为了增加代码的可读性,我们一般还会用到enum枚举类型来增加代码的可读性。
enum
{
exi,//0
add,//1
show,//2
search,//3
modify,//4
del,//5
sort//6
};
int main()
{
int input = 0;
//创建通讯录
struct contact con;//con包含了1000个通信录信息,和size
//初始化通讯录
Initcontact(&con);
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case add:
Addcontact(&con);//1
break;
case show:
Showcontact(&con);//2
break;
case search:
Searchcontact(&con);//3
break;
case modify:
Modifycontact(&con);//4
break;
case del:
Delcontact(&con);//5
break;
case sort:
Sortcontact(&con);//6
break;
case 0:
printf("退出通讯录\n");
break;
default:
printf("输入错误,重新输入\n");
break;
}
} while (input);
return 0;
}
我们要输入成员的信息,就要用到结构体,将需要的成员的信息定义在结构体当中,在输出的时候就会很方便,但是我们要知道的的是,我们添加成员肯定不止是添加一个成员的,所以还要用到结构体数组,这要就可以存放多个成员了。
具体看以下代码:
struct peoinfo
{
char name[MAX_NAME];
int age;
char sex[MAX_SEX];
char tele[MAX_TELE];
char addr[MAX_ADDR];
};
//定义一个通讯录类型,里面存放通讯录信息和记录有多少个信息
struct contact
{
struct peoinfo date[MAX];//定义一个结构体数组,里面可以存放MAX个成员。
int size;//记录当前信息个数
};
这里需要解释的就是,我们将一个成员结构体定义在了另一个结构体当中,并且在此结构体当中定义了结构体数组,同时还定义了size变量。这里解释一下,我们设计出这个通讯录是给用户用的,但是我们不知道用户会添加多少个成员,所以我们就得定义一个变量来记录添加了多少个成员,而这个变量就是size。于是当我们传参的时候就得把成员结构体和size传过去Addcontact(&con,sizr);,其他的也是如此,而没个功能都是要传这两个参数的,这就显得有点麻烦了,既然这两个参数是同时传过去的,那我们我们就把他们两个放在一起,到时候传参的时候就只要传一个参数即可,这样就简化了代码。
最后就是我们要用到的全局变量和所用到的头文件:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<assert.h>
#define MAX 1000 //最多可以放下1000个成员
#define MAX_NAME 20 //名字的最大长度是20
#define MAX_SEX 5
#define MAX_TELE 20
#define MAX_ADDR 20
至此,一个通讯录的基本框架就算是完成了,接下来就是逐个的实现通讯录的功能了。
我们定义了结构体数组,但是没有进行初始化,此时结构体数组里面存放的就是随机值,这避免不了在后续的程序中会出现一些问题,所以这里我们就将所有的成员初始化为0,size也初始化为0,这里就要用到字符串函数memset内存设置函数的头文件
void Initcontact(struct contact* ps)
{
assert(ps!=NULL);
memset(ps->date, 0, sizeof(ps->date));
ps->size = 0;//设置通讯录最初是0
}
添加成员的时候我们要考虑以下几点:1:成员添加的数量是否超过了给点数组的大小,2:成员添加了多要个。这两点都会影响后续的进行。而成员添加的的多少由size记录,我们知道数组的下标是从0开始的,我们第一个成员添加到下标为0出的数组里面,那如果我们还想添加成员,那接下来就要添加到下标为1出的数组,所以我们在每添加一个成员的时候size都要++。
void Addcontact(struct contact* ps)
{
assert(ps!=NULL);
if (ps->size == MAX)
{
printf("通讯录已满,无法增加\n");
}
else
{
printf("请输入名字;>");
scanf("%s", ps->date[ps->size].name);
printf("请输入年龄;>");
scanf("%d", &(ps->date[ps->size].age));
printf("请输入性别;>");
scanf("%s", ps->date[ps->size].sex);
printf("请输入电话;>");
scanf("%s", ps->date[ps->size].tele);
printf("请输入地址;>");
scanf("%s", ps->date[ps->size].addr);
ps->size++;
}
}
上面我们知道了用户添加了都少个成员,即size个成员,有了个数我们就可以很好的将其打印出来,即用一个for循环即可:
void Showcontact(const struct contact* ps)//查找成员是不修改参数的,所以这里可以用const修饰
{
assert(ps!=NULL);
if (ps->size == 0)//没有添加成员的时候或者成员都被删除了
{
printf("通讯录为空\n");
}
else
{
printf("%-20s\t%-4s\t%-4s\t%-12s\t%-10s\n", "名字", "年龄", "性别", "电话", "住址");
int i = 0;
for (i = 0; i < ps->size; i++)
{
printf(" %-20s\t%-4d\t%-4s\t%-12s\t%-10s\n",
ps->date[i].name,
ps->date[i].age,
ps->date[i].sex,
ps->date[i].tele,
ps->date[i].addr);
}
}
}
查找成员的时候我们一般用的方法是直接用一个for循环,然后一一遍历数组,方法如下:
Searchcontact(&con);
{
assert(ps!=NULL);
char names[MAX_NAME];
scanf("%s", names);
int i = 0;
for (i = 0; i < ps->size; i++)
{
if (strcmp(ps->date[i].name, names) == 0)
{
//查到了此人,再将其打印出来。
}
else
{
printf("没有此人");
}
}
}
但是我们会发现,在后面的成员修改和成员删除,都是要先查找出有这个成员了再进行修改和删除,那如果是上面这样的写法的话,那每个功能函数都要添加这段代码,那代码就重复累赘了,所以我们就想到了用一个函数find将其分装好来,要用的时候就调用这个函数。
int find(const struct contact* ps)
{
assert(ps!=NULL);
char names[MAX_NAME];
scanf("%s", names);
int i = 0;
//寻找到要查找的人
for (i = 0; i < ps->size; i++)
{
if (strcmp(ps->date[i].name, names) == 0)
{
return i;//找到返回下标
}
}
return -1;//没有此人返回-1
}
void Searchcontact(const struct contact* ps)
{
assert(ps!=NULL);
char names[MAX_NAME];
if (ps->size == 0)
{
printf("通讯录为空,无法查询\n");
}
printf("请输入查询的名字:>");
int ret = find(ps);
if (ret!=-1)
{
printf("%-20s\t%-4s\t%-4s\t%-12s\t%-10s\n", "名字", "年龄", "性别", "电话", "住址");
printf(" %-20s\t%-4d\t%-4s\t%-12s\t%-10s\n",
ps->date[ret].name,
ps->date[ret].age,
ps->date[ret].sex,
ps->date[ret].tele,
ps->date[ret].addr);
}
else
{
printf("没有此人\n");
}
}
到这里成员的修改就会比较方便,就是再查找到成员的时候进行修改就可以了。
void Modifycontact(struct contact* ps)
{
assert(ps!=NULL);
printf("请输入要修改人的名字:>");
//查找要修改人的为位置
int ret=find(ps);
if (ret != -1)
{
printf("修改后的名字;>");
scanf("%s", ps->date[ret].name);
printf("修改后的年龄;>");
scanf("%d", &(ps->date[ret].age));
printf("修改后的性别;>");
scanf("%s", ps->date[ret].sex);
printf("修改后的电话;>");
scanf("%s", ps->date[ret].tele);
printf("修改后的地址;>");
scanf("%s", ps->date[ret].addr);
printf("修改后的通讯录\n");
//打印修改后的通讯录
Showcontact(ps);
}
else
{
printf("要修改的人不存在\n");
}
}
删除成员的话第一步也是先查找出有这个人,然后就是进行删除。关键是怎么实现删除这个功能。我们使用数组存放着成员的信息,如果说直接将要删除的人从数组中去掉,那显然是不可能的,因为如果是直接去掉的话那这个存放成员的内容就是空的,那后面要展示成员的时候就会把这个空的数组展示出来,这就不符合我们要的需求。我们既要函数这个成员还好不影响数组的遍历,所以我们就可以使用平移法,就是就是将要删除的那个成员的后面的成员全部向前平移一个单位,同时我们的成员也少了一个,size要–;
void Delcontact(struct contact* ps)
{
assert(ps!=NULL);
printf("请输入要删除人的名字:>");
//查找要删除人的位置
int ret = find(ps);
//删除
if (ret != -1)
{
int i = 0;
for (i = ret; i < ps->size-1; i++)
{
ps->date[i] = ps->date[i + 1];
}
ps->size--;
printf("删除成功\n");
printf("删除后的通讯录\n");
Showcontact(ps);
}
else
{
printf("要删除的人不存在\n");
}
}
最后就到了排序阶段了,这里我们是按照年龄来进行排序的,这里就是直接使用冒泡排序就行了。
void Sortcontact(struct contact* ps)
{
assert(ps!=NULL);
int i = 0;
//冒泡排序
for (i = 0; i < ps->size - 1; i++)
{
int j = 0;
for (j = 0; j < ps->size - 1 - i; j++)
{
if (ps->date[j].age > ps->date[j+1].age)
{
struct peoinfo tmp = ps->date[j];//要创建相同类型的
ps->date[j] = ps->date[j + 1];
ps->date[j + 1] = tmp;
}
}
}
printf("排序成功\n");
printf("排序后的通讯录\n");
//打印排序后的通讯录
Showcontact(ps);
}
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<assert.h>
#define MAX 1000
#define MAX_NAME 20
#define MAX_SEX 5
#define MAX_TELE 20
#define MAX_ADDR 20
struct peoinfo
{
char name[MAX_NAME];
int age;
char sex[MAX_SEX];
char tele[MAX_TELE];
char addr[MAX_ADDR];
};
//定义一个通讯录类型,里面存放通讯录信息和记录多少个信息
struct contact
{
struct peoinfo date[MAX];
int size;//记录当前信息个数
};
enum
{
exi,//0
add,//1
show,//2
search,//3
modify,//4
del,//5
sort//6
};
//函数的声明
//初始化通讯录
void Initcontact(struct contact* ps);
//增加通讯录
void Addcontact(struct contact* ps);
//展示通讯录
void Showcontact(const struct contact* ps);
//查找通讯录
void Searchcontact(const struct contact* ps);
//修改通讯录
void Modifycontact(struct contact* ps);
//删除通讯录
void Delcontact(struct contact* ps);
//通讯录排序(按照年龄排序)
void Sortcontact(struct contact* ps);
//函数的实现
void Initcontact(struct contact* ps)
{
assert(ps!=NULL);
memset(ps->date, 0, sizeof(ps->date));
ps->size = 0;//设置通讯录最初是0
}
void Addcontact(struct contact* ps)
{
assert(ps!=NULL);
if (ps->size == MAX)
{
printf("通讯录已满,无法增加\n");
}
else
{
printf("请输入名字;>");
scanf("%s", ps->date[ps->size].name);
printf("请输入年龄;>");
scanf("%d", &(ps->date[ps->size].age));
printf("请输入性别;>");
scanf("%s", ps->date[ps->size].sex);
printf("请输入电话;>");
scanf("%s", ps->date[ps->size].tele);
printf("请输入地址;>");
scanf("%s", ps->date[ps->size].addr);
ps->size++;
}
}
void Showcontact(const struct contact* ps)
{
assert(ps!=NULL);
if (ps->size == 0)
{
printf("通讯录为空\n");
}
else
{
printf("%-20s\t%-4s\t%-4s\t%-12s\t%-10s\n", "名字", "年龄", "性别", "电话", "住址");
int i = 0;
for (i = 0; i < ps->size; i++)
{
printf(" %-20s\t%-4d\t%-4s\t%-12s\t%-10s\n",
ps->date[i].name,
ps->date[i].age,
ps->date[i].sex,
ps->date[i].tele,
ps->date[i].addr);
}
}
}
static int find(const struct contact* ps)
{
assert(ps!=NULL);
char names[MAX_NAME];
scanf("%s", names);
int i = 0;
for (i = 0; i < ps->size; i++)
{
if (strcmp(ps->date[i].name, names) == 0)
{
return i;
}
}
return -1;
}
void Searchcontact(const struct contact* ps)
{
assert(ps!=NULL);
char names[MAX_NAME];
if (ps->size == 0)
{
printf("通讯录为空,无法查询\n");
}
printf("请输入查询的名字:>");
int ret = find(ps);
if (ret != -1)
{
printf("%-20s\t%-4s\t%-4s\t%-12s\t%-10s\n", "名字", "年龄", "性别", "电话", "住址");
printf(" %-20s\t%-4d\t%-4s\t%-12s\t%-10s\n",
ps->date[ret].name,
ps->date[ret].age,
ps->date[ret].sex,
ps->date[ret].tele,
ps->date[ret].addr);
}
else
{
printf("没有此人\n");
}
}
void Modifycontact(struct contact* ps)
{
assert(ps!=NULL);
printf("请输入要修改人的名字:>");
int ret = find(ps);
if (ret != -1)
{
printf("修改后的名字;>");
scanf("%s", ps->date[ret].name);
printf("修改后的年龄;>");
scanf("%d", &(ps->date[ret].age));
printf("修改后的性别;>");
scanf("%s", ps->date[ret].sex);
printf("修改后的电话;>");
scanf("%s", ps->date[ret].tele);
printf("修改后的地址;>");
scanf("%s", ps->date[ret].addr);
printf("修改后的通讯录\n");
//打印修改后的通讯录
Showcontact(ps);
}
else
{
printf("要修改的人不存在\n");
}
}
void Delcontact(struct contact* ps)
{
assert(ps!=NULL);
printf("请输入要删除人的名字:>");
//查找要删除人的位置
int ret = find(ps);
//删除
if (ret != -1)
{
int i = 0;
for (i = ret; i < ps->size - 1; i++)
{
ps->date[i] = ps->date[i + 1];
}
ps->size--;
printf("删除成功\n");
printf("删除后的通讯录\n");
Showcontact(ps);
}
else
{
printf("要删除的人不存在\n");
}
}
void Sortcontact(struct contact* ps)
{
assert(ps!=NULL);
int i = 0;
//冒泡排序
for (i = 0; i < ps->size - 1; i++)
{
int j = 0;
for (j = 0; j < ps->size - 1 - i; j++)
{
if (ps->date[j].age > ps->date[j + 1].age)
{
struct peoinfo tmp = ps->date[j];//要创建相同类型的
ps->date[j] = ps->date[j + 1];
ps->date[j + 1] = tmp;
}
}
}
printf("排序成功\n");
printf("排序后的通讯录\n");
//打印排序后的通讯录
Showcontact(ps);
}
void menu()
{
printf("**************** Menu *****************\n");
printf("***** 1.add 2.show *****\n");
printf("***** 3.search 4.modify *****\n");
printf("***** 5.del 6.sort *****\n");
printf("***** 0.exit *****\n");
printf("***************************************\n");
}
//主函数部分
int main()
{
int input = 0;
//创建通讯录
struct contact con;//con包含了1000个通信录信息,和size
//初始化通讯录
Initcontact(&con);
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case add:
Addcontact(&con);//1
break;
case show:
Showcontact(&con);//2
break;
case search:
Searchcontact(&con);//3
break;
case modify:
Modifycontact(&con);//4
break;
case del:
Delcontact(&con);//5
break;
case sort:
Sortcontact(&con);//6
break;
case 0:
printf("退出通讯录\n");
break;
default:
printf("输入错误,重新输入\n");
break;
}
} while (input);
return 0;
}