其他分享
首页 > 其他分享> > 简单易上手的通讯录实现,跟着敲,你也能拥有属于你的通讯录!(代码+笔记已经上传至gitee)

简单易上手的通讯录实现,跟着敲,你也能拥有属于你的通讯录!(代码+笔记已经上传至gitee)

作者:互联网

通讯录

老规矩笔记和代码欢迎自取~
链接:

  1. 通讯录笔记
  2. 通讯录工程文件+源代码

文章目录


一、通讯录的组成

利用最近所学的知识,试着实现一个通讯录

手机里面的通讯录信息

在这里插入图片描述

最后我决定给通讯录增加以下信息


二、通讯录文件构成

为什么每一篇小项目都强调一遍文件构成?

  • 文件的构成是每一个项目的思路
  • 没有思路,直接上手容易手忙脚乱
  • 分析好每个文件所包含的内容,有利于我们代码的书写

1. test.c

按照之前的设计小游戏一样,test.c文件是必要的,用来测试各种功能使用是否可以正常使用或者运行

还包括整个通讯录的框架,比如提供给使用者得选择菜单

2. correspondence.c

用来设计实现通讯录功能的文件,文件包含的基本上都是函数

函数包括实现增加/删除/修改/查找/打印/排序联系人

3. correspondence.h

包含 test.c 和 correspondence.c 中需要用到的库函数的头文件,以及全过程需要使用的变量


三、实现的代码步骤分析

1. 打印菜单

使用者上手即操作,我们需要提供给他们操作的菜单,也是我们功能的目录

菜单明细上面也分析了,主要包含:

void menu()//菜单
{
	printf("==============通讯录=============\n");
	printf("         1.添加联系人(add)       \n");
	printf("         2.查找联系人(seek)      \n");
	printf("         3.删除联系人(delete)    \n");
	printf("         4.修改联系人(modify)    \n");
	printf("         5.排序联系人(sort)      \n");
	printf("         6.打印联系人(print)     \n");
	printf("         0.退出通讯录(EXIT)      \n");

}

利用最近所学的枚举类型,我们试着这次的循环内的switch语句,判断不选择数字,而选择判断功能的内容

所以我们定义一个枚举类型,用单词代表各个功能

此过程在 test.c 文件中

enum menu
{
	EXIT,//0
	add,//1
	seek,//2
	delete,//3
	modify,//4
	sort,//5
	print//6
};

把exit放前面正好代表0,每个枚举常量代表的数字都是对应的功能


到此为止,整个循环的大概模型是这样代码如下

此过程在 test.c 文件中

int main()
{
	int input = 0;
	do
	{
		menu();//打印菜单提供使用者选择
		printf("请选择您要使用的功能(输入选项括号内内容):");
		scanf("%d", &input);//使用者输入选择

		switch (input)
		{
		case add:break;
		case seek:break;
		case delete:break;
		case modify:break;
		case sort:break;
		case print:break;
		case exit:
			printf("您选择了退出通讯录\n");
			break;
		default:
			printf("输入错误信息,请重新输入:\n");
			break;
		}
	} while (input != 0);
	return 0;
}

运行的结果

分别测试了 正确信息 错误信息 退出功能

在这里插入图片描述


2. 联系人信息初始化

刚拿到新手机的大家,通讯录里面是没有联系人的信息

但可以通过自己填写联系人信息存储到手机中

我们需要提供给使用者,接收/存储信息的一个数据库

但因为人的信息是复杂的,是多种元素构成

信息包括:姓名 + 性别 + 年龄 + 电话 + 公司地址

使用类型:char char int int char

此过程在 correspondence.h 文件中

#define NAME_MAX 11
#define GENDER_MAX 5
#define TELE_MAX 12
#define EMAIL_MAX 20

//通讯录初始化个人信息
struct perinfmt //personal information
{
	char name[NAME_MAX];//支持5个汉字(2个字节一个汉字)
	char gender[GENDER_MAX];//男性 or 女性
	int age;
	char tele[TELE_MAX];//11位电话号码
	char email[EMAIL_MAX];//19位邮箱
};

为了不用每次挨个修改个人信息的大小,我们用define定义每个信息的最大值


还没有结束,我们创建好的是每个人的信息填写位置,但还没有创建一个通讯录,有100个人,每个人还需要标记序号(这里序号不放在个人信息里是因为,创建联系人的时候不会去填每个人的信息),这是需要我们系统内部自己去偷偷记录的

此时100个人 + 序号 通讯录仍然是复杂信息 我们再次创建结构体变量

此过程在 correspondence.h 文件中

struct address_book //通讯录内容
{
	struct perinfmt p[BOOK_MAX];//每个人信息,数组一共100个人
	int ID;//统计每个人编号
};

创建通讯录的结构体变量时,我们仍然还没有初始化

新建一个函数,专门初始化它

此过程在 correspondence.c 文件中

void Initialize(struct address_book* ap)
{
	ap->ID = 0;//序号初始值0
	memset(ap->p, 0, sizeof(ap->p));//初始化整个结构体数组大小为0
	
}

记得在 correspondence.h 中声明

我们才能在 test.c 上使用 (记得在进入循环前就初始化好

struct address_book alinfmt;//all information
Initialize(&alinfmt);//初始化通讯录

PS:但其实也可以不创建这个 函数初始化

(我们是为了方便,这样每次都可以,直接用函数初始化)

可以在创建变量的时候直接初始化

struct address_book alinfmt = { { 0 }, 0 };//all information

此过程在 test.c 中完成


3. 添加联系人

功能的铺垫已经写好了

我们开始写主要的功能

添加联系人函数

//增加联系人
void add_contact(struct address_book* ap)
{
	if (ap->ID == BOOK_MAX)
	{
		printf("通讯录满了,请删除一些联系人再添加!\n");
	}
	else
	{
		printf("请输入联系人姓名:");
		scanf("%s", ap->p[ap->ID].name);

		printf("请输入联系人性别:");
		scanf("%s", ap->p[ap->ID].gender);

		printf("请输入联系人年龄:");
		scanf("%d", &(ap->p[ap->ID].age));
        //这里是因为age是int类型变量需要传地址,其他数组类型变量名就是地址

		printf("请输入联系人电话:");
		scanf("%s", ap->p[ap->ID].tele);

		printf("请输入联系人邮箱地址:");
		scanf("%s", ap->p[ap->ID].email);

		printf("-----添加完成-----\n");
		ap->ID++;
	}
}

scanf里面一大串都是什么?

图解

在这里插入图片描述

还有写这段代码时候必须包含等号,不能只写大于号

if (ap->ID == BOOK_MAX)
	{
		printf("通讯录满了,请删除一些联系人再添加!\n");
	}

不然会警告

在这里插入图片描述

最后别忘了填写完一个人的信息的时候,记录的ID需要增加


4. 打印联系人

既然已经完成了添加联系人,那么我们就不按顺序,看看如何打印我们所有联系人的成员吧

打印联系人函数

直接用一个for循环搞定~

//显示所有联系人
void print_book(struct address_book* ap)
{
	int i = 0;
	for (i = 0; i < ap->ID; i++)
	{
		printf("联系人姓名:%s\n性别:%s\n年龄:%d\n电话:%s\n邮箱地址:%s\n", 
			ap->p[i].name, 
			ap->p[i].gender, 
			ap->p[i].age,
			ap->p[i].tele,
			ap->p[i].email);
	}
}

搭配添加联系人食用~,结果如下图:

在这里插入图片描述


5. 删除联系人

我们发现,删除/查找/修改 联系人功能中,都会包含有 查找联系人这个动作

用for循环遍历一遍,查找是否有这个联系人

//查找联系人
int find_contact(const struct address_book* ap, const char* name)
{
	int i = 0;
	for (i = 0; i < ap->ID; i++)
	{
		if (strcmp(ap->p[i].name, name) == 0)
		{
			return 1;
		}
	}
	return -1;
}

找到了之后图解:

在这里插入图片描述

//删除联系人
void del_contact(struct address_book* ap)
{
	if (ap->ID == 0)//判断通讯录是否为空
	{
		printf("无可删除联系人");
		return;
	}

	char name[NAME_MAX] = { 0 };//存放查找的姓名
	printf("请输入删除的联系人姓名:");
	scanf("%s", name);
	int ret = find_contact(ap, name);

	if (ret == -1)
	{
		printf("该联系人不存在");
	}
	else
	{
		//删除联系人
		int j = 0;
		for (j = ret; j < ap->ID - 1; j++)
		{
			ap->p[j] = ap->p[j + 1];
		}
		ap->ID--;//少了一个数字

		printf("删除成功!\n");
	}

}

代码运行效果:

在这里插入图片描述

在这里插入图片描述

我的舍友就这样成功被我删除了哈哈哈哈


6. 查找指定联系人

这个代码有了上面几个代码的铺垫,直接复制粘贴修改一些变量就可以!

看看代码是不是有点熟悉,copy就完事了

//查找指定联系人
void seek_contact(const struct address_book* ap)//我们只是查找不作修改
{
	char name[NAME_MAX];
	printf("请输入需要查找的联系人姓名:");
	scanf("%s", &name);

	int ret = find_contact(ap, name);

	if (ret == -1)
	{
		printf("该联系人不存在");
	}
	else
	{
		printf("找到了!\n联系人姓名:%s\n性别:%s\n年龄:%d\n电话:%s\n邮箱地址:%s\n\n",
			ap->p[ret].name,
			ap->p[ret].gender,
			ap->p[ret].age,
			ap->p[ret].tele,
			ap->p[ret].email);
	}
}

运行效果:

在这里插入图片描述


7. 修改联系人

同理,也是copy + 稍微修改一下就完事了

//修改联系人
void modify_contact(struct address_book* ap)
{
	char name[NAME_MAX];
	printf("请输入需要查找的联系人姓名:");
	scanf("%s", &name);

	int ret = find_contact(ap, name);

	if (ret == -1)
	{
		printf("该联系人不存在");
	}
	else
	{
		printf("开始修改联系人信息!\n");

		printf("请重新输入联系人姓名:");
		scanf("%s", ap->p[ret].name);

		printf("请重新输入联系人性别:");
		scanf("%s", ap->p[ret].gender);

		printf("请重新输入联系人年龄:");
		scanf("%d", &(ap->p[ret].age));

		printf("请重新输入联系人电话:");
		scanf("%s", ap->p[ret].tele);

		printf("请重新输入联系人邮箱地址:");
		scanf("%s", ap->p[ret].email);

		printf("-----修改完成-----\n");

	}

}

运行效果:

在这里插入图片描述

在这里插入图片描述


8. 排序联系人

我们用qsort快排进行联系人的姓名排序

int compare(const void* e1, const void* e2)
{
	return (strcmp((const char*)e1, (const char*)e2));
}

//排序联系人
void sort_contact(struct address_book* ap)
{

	qsort(ap->p->name, ap->ID, sizeof(ap->p[0]), compare);
	printf("排序完成,请选择显示所有联系人进行查看!\n");

}

然后,我将前面的exit改成了大写

因为出现了问题!!!

在stdlib.h文件的存在情况下,exit是已经被使用的

而我再使用,与库函数冲突,会报错!!

在发现了原因的情况下,修改之后

效果如下:

在这里插入图片描述


标签:name,易上,联系人,ret,gitee,ap,通讯录,printf
来源: https://blog.csdn.net/qq_53656490/article/details/120615925