拿到通讯录,大伙用它干什么呢?
无非就是存储朋友同学的信息,比如:姓名,地址,电话,性别等一系列他的消息。
今天就来实现一个可以容纳一千人的具有增加,删除,查找,修改,排序,展示,退出等功能的通讯录。
写代码要有逻辑,依靠目的和功能去写代码。首先明确为什么写这行代码,然后再怎么去实现它。
主函数的逻辑
先看主函数,一系列的模块功能,用函数去封装,先不考虑这些函数怎么实现,就看逻辑和过程,想实现一个上述功能的通讯录,这些函数是必不可少的吧,每一步的安排对应每一项功能。
主函数也就几十行的代码,语句都非常简单,整体逻辑框架构思好,只需要往里面添砖加瓦就行,逐步实现每一步的函数,即可。
OK,主函数敲定后,要解决每一步的函数,尽量不要都放在主函数里面,因为那样会非常乱。。这样把他们放在另一个.C文件里面,单独是存放函数。然后函数声明,以及结构体的定义,和宏定义,放在单独的一个头文件.h里面。
头文件里面的各种声明
其实,也简单,只要主函数里面用到的函数,都需要声明一下,就在这个头文件里面声明,一一对应即可。后面将介绍前面两个结构体的作用。
结构体的定义
这是放在头文件.h里面的代码,一系列的宏定义,以后想改数字,方便。以及人的信息,用结构体定义人的信息。并且用了别名,使后续结构体使用起来方便。结构体内包含:姓名,年龄,性别,电话,地址。其中除了年龄是整型,其余全是字符数组。
还有一个结构体是通讯录的,里面放的是人的信息的结构体,这属于结构体的嵌套定义,并且因为要容纳一千人,所以用的是结构体数组,用来存放人的信息。另外,定义一个整型count用来记录当前通讯录中实际人的个数。并且也是用了别名,这样方便后面的使用。
各模块函数的实现
1,初始化通讯录的函数
不需要返回值,所以用void,传参用的是通讯录的指针也就是结构体指针,因为后续肯定要修改里面的信息。用地址传值最为合理。
基本上是传指针的函数,第一步都需要进行断言,防止指针没有意义,这是必备一步,不止这个函数,其余任何地方,任何函数,只要是传的指针,都需要,大伙一定要养成这个习惯啊。
然后将定义的记录的数count初始化为0,然后用memset库函数把通讯录结构体里面的,存放人的信息结构体数组data初始化为0。
2,添加联系人的函数
断言部分就不用说了。
先判断数量是否以及达到最大值Max,也就是1000,之前宏定义时说过。达到最大值则不能添加了。
没有达到,则进行添加步骤,一系列的输入信息,最后一定要记住count++,在结构体数组里面,往后推一个元素。
大伙很疑惑,count的作用?就是在这里体现出来的,往后推下一个数组的元素,用count即可。类比普通数组 *p是第一个元素,之后是*(p+1),*(p+2)等等。count++就可以达到效果。
3,删除联系人的函数
当我们想删除一个成员的时候,先输入我们要删除的成员某一个信息,比如姓名,然后再拿输入的这个信息来和通讯录里已存的信息来比较,当找到这条信息之后再进行删除操作。
在删除之前我们要先进行一次查找已有信息的操作,后面的查找是不是也要查找一个人的信息,而修改也要查找一个人的信息。
但是怎么找到想删除的成员呢?
也就是说这个查找功能好几个函数都要用到,于是我们把这个查找功能封装在实现函数的文件内部,这个函数不需要向外部声明,因为仅仅只是在通讯录源文件内部使用。加上static修饰就行了
先看,查找的函数
传值传个结构体指针是必须的,然后传一个名字,才知道查找的对象信息。然后循环遍历所有联系人的名字信息,用库函数strcmp去比较,找到的时候,返回那个元素的下标 i。*(p+i)就是那个联系人的信息了。找不到就返回-1,-1本来就是不存在的。
注释也写了,加上static的作用。
接下来看,删除的函数
首先我们要判断通讯录中是否有成员,如果没有成员,那么也就没有必要查找元素删除了。
判断有成员之后,我们先输入要删除成员的名字,然后调用查找函数找到这个成员并且返回它的下标,如果没找到就提示没找到,如果找到了我们就来进行删除操作。
这里的变量pos是所找到成员的下标,然后通过一个循环来进行成员覆盖。这里我们来判断一下循环次数,假如按照我上面举的例子,12345,要删除3,返回下标是pos = 2,而我们要覆盖的次数是3次,这里我们知道通讯录的成员个数是sz,所以sz-pos-1就是我们要循环的次数了。定义初始变量为pos,判断语句为sz-1,正好循环sz-pos-1次。
删除操作就是结构体的赋值,把后一个下标元素的值,覆盖到前一个下标元素上面。
删除完之后记得要给成员数sz减1,否则最后一个成员的内容还在那放着。
4,查找功能的函数
这个实现,肯定简单,因为前面已经实现好一个查找函数了,拿过来直接用即可,只需要稍微加一些修饰。只要找到了,就打印出来具体的信息。
5,展示功能的函数
展示函数接收的参数和返回类型和增加函数是一样的。
打印通讯录内容之前我们先打印一个表头,目的是方便查找。打印的时候我们可以估算一下各个信息的长度,然后打印
由于通讯录中可能有多条信息,所以打印的时候采用一个循环来打印,打印的次数就是有效信息数sz的值。打印的方法使用的是结构体基础知识,结构体成员的访问,这里就不再多提了。
6,修改功能的函数
修改开始前和删除是一样的,首先要找到修改的元素,这里使用的还是前面所写的查找函数,判断它的返回值。找到下标之后进行修改。修改就得重新输入信息。一系列的输入
7 ,排序功能的函数
排序同样,我们要根据成员的某一个信息来排序,可以按照名字来排序,也可以按照年龄来排序等等,这里还是使用姓名来排序。我们这里用升序排列。
字符串大小的比较就是使用库函数qsort,这是专门的排序函数。如果对qsort库函数不熟悉的好兄弟,我前面有篇博客,写的就是qsort函数,模拟实现qsort。其中调用了库函数strcmp比较的是这些字符串的ASCII码值。第一个大于第二个字符串返回大于0的数,小于返回小于0的数,等于返回0。
ok,这样一个通讯录就能实现了,看一看实际效果,每个功能都能实现
其实这样实现,还有一些缺陷,要是有一万个人,怎么办?
其实以后要是用到动态内存管理,就可以解决这种问题了。
下面把全部代码都奉上各位老爷。。
contact.h
contact.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
void InitContact(Contact* pc)
{
assert(pc);
pc->count = 0;
memset(pc->data, 0, sizeof(pc->data));
}
void AddContact(Contact* pc)
{
assert(pc);
if (pc->count == Max)
{
printf("通讯录已满,无法添加\n");
return ;
}
printf("请输入名字:>");
scanf("%s", pc->data[pc->count].name);
printf("请输入年龄:>");
scanf("%d", &(pc->data[pc->count].age));
printf("请输入性别:>");
scanf("%s", pc->data[pc->count].sex);
printf("请输入电话:>");
scanf("%s", pc->data[pc->count].tele);
printf("请输入地址:>");
scanf("%s", pc->data[pc->count].addr);
pc->count++;
printf("增加成功\n");
}
void ShowContact(const Contact* pc)
{
assert(pc);
int i = 0;
printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "名字", "年龄", "性别", "电话", "地址");
for (i = 0; i < pc->count; i++)
{
printf("%20s\t%3d\t%5s\t%12s\t%30s\n", pc->data[i].name, pc->data[i].age,
pc->data[i].sex,
pc->data[i].tele,
pc->data[i].addr);
}
}
static int FindByName(Contact* pc, char name[]) //加上static修饰,只能在这个.c文件内部使用
{
assert(pc);
int i = 0;
for (i = 0; i < pc->count; i++)
{
if (strcmp(pc->data[i].name, name) == 0)
{
return i;
}
}
return -1;
}
void DelContact(Contact* pc)
{
assert(pc);
int i = 0;
char name[Max_NAME] = { 0 };
if (pc->count == 0)
{
printf("通讯录为空\n");
return;
}
printf("请输入要删除人的名字:>");
scanf("%s", name);
//查找
int pos = FindByName(pc, name);
if (pos == -1)
{
printf("要删除的人不存在\n");
return;
}
//删除
for (i = pos; i < pc->count-1; i++)
{
pc->data[i] = pc->data[i + 1];
}
pc->count--;
printf("删除成功\n");
}
void SearchContact(Contact* pc)
{
assert(pc);
char name[Max_NAME] = { 0 };
printf("请输入要查找人的名字:>");
scanf("%s", name);
//查找
int pos = FindByName(pc, name);
if (pos == -1)
{
printf("要查找的人不存在\n");
return;
}
//打印
else
{
printf("%-20s\t%-5s\t%-5s\t%-12s\t%-30s\n", "名字", "年龄", "性别", "电话", "地址");
printf("%20s\t%3d\t%5s\t%12s\t%30s\n", pc->data[pos].name, pc->data[pos].age,
pc->data[pos].sex,
pc->data[pos].tele,
pc->data[pos].addr);
}
}
//修改指定联系人
void ModifyContact(Contact* pc)
{
assert(pc);
assert(pc);
char name[Max_NAME] = { 0 };
printf("请输入要修改人的名字:>");
scanf("%s", name);
//查找
int pos = FindByName(pc, name);
if (pos == -1)
{
printf("要修改的人不存在\n");
return;
}
//修改
printf("要修改人的信息已经查找到,接下来开始修改\n");
printf("请输入名字:>");
scanf("%s", pc->data[pos].name);
printf("请输入年龄:>");
scanf("%d", &(pc->data[pos].age));
printf("请输入性别:>");
scanf("%s", pc->data[pos].sex);
printf("请输入电话:>");
scanf("%s", pc->data[pos].tele);
printf("请输入地址:>");
scanf("%s", pc->data[pos].addr);
printf("修改成功\n");
}
// 排序
//按照名字来排序
//可以按照年龄来排序
int com_peo_by_name(const void* e1, const void* e2)
{
return strcmp(((PeoInfo*)e1)->name, ((PeoInfo*)e2)->name);
}
void SortContact(Contact* pc)
{
assert(pc);
qsort(pc->data, pc->count, sizeof(PeoInfo), com_peo_by_name);
printf("排序成功\n");
}
主函数部分
#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
void menu() //模拟菜单, 显得专业
{
printf("**********************************\n");
printf("*** 1. add 2.del **\n");
printf("*** 3.search 4.modift **\n");
printf("*** 5.show 6.sort **\n");
printf("*** 0.exit **\n");
printf("**********************************\n");
}
int main()
{
int input = 0;
Contact con; //通讯录
//初始化通讯录
InitContact(&con);
do // 大循环,这样执行之后,可以随意操作通讯录
{
menu();
printf("请选择\n");
scanf("%d", &input);
switch (input)
{
case 1:
AddContact(&con); //添加联系人的函数
break;
case 2:
DelContact(&con); //删除联系人的函数
break;
case 3:
SearchContact(&con); //查找联系人的函数
break;
case 4:
ModifyContact(&con); //修改联系人函数
break;
case 5:
ShowContact(&con); //展示联系人的函数
break;
case 6:
SortContact(&con); //排序的函数
break;
case 0:
printf("退出通讯录\n");
break;
default:
printf("选择错误\n");
break;
}
} while (input);
return 0;
}