C语言,实现通讯录功能

拿到通讯录,大伙用它干什么呢?

无非就是存储朋友同学的信息,比如:姓名,地址,电话,性别等一系列他的消息。

今天就来实现一个可以容纳一千人的具有增加,删除,查找,修改,排序,展示,退出等功能的通讯录。

写代码要有逻辑,依靠目的和功能去写代码。首先明确为什么写这行代码,然后再怎么去实现它。

主函数的逻辑

先看主函数,一系列的模块功能,用函数去封装,先不考虑这些函数怎么实现,就看逻辑和过程,想实现一个上述功能的通讯录,这些函数是必不可少的吧,每一步的安排对应每一项功能。

主函数也就几十行的代码,语句都非常简单,整体逻辑框架构思好,只需要往里面添砖加瓦就行,逐步实现每一步的函数,即可。

 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;
}

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值