2020-12-19

C语言实现初阶通讯录

  本篇主要介绍C语言实现初阶通讯录

文章目录


前言

本篇主要介绍C语言实现通讯录。通讯录涵盖初阶包括进阶C语言的许多知识点,包括但不限于指针,动态内存分配,文件操作,结构体的运用。
这篇博客是初阶通讯录,即不涉及动态内存以及文件操作。完整版我会在后续发布,在这个版本的基础上进行一定的修改。
下面开始


一、功能介绍

1,增加成员信息
2,删除成员信息
3,搜索成员信息
4,修改成员信息
5,排序成员信息
6,打印成员信息

二、模板构建

通讯录模板 的构建是通过结构体来实现的。
这里需要两个结构体,一个是struct PeoInfo,用来创建用户信息类型,包括姓名,年龄,电话,性别,住址。另一个是struct Contact,用来创建通讯录类型,该类型包含了两个元素,其中一个是数组:struct PeoInfo data[1000],即该通讯录可容纳1000人,另一个是size,即你要存的是第几个人(相当于把这个人存入数组的哪个位置)

typedef struct PeoInfo
{
	char name[5];
	char sex[5];
	int age;
	char address[20];
	char tel[12];
}PeoInfo;
typedef struct Contact
{
	PeoInfo data[1000];
	int size;
}Contact;

因此,我们便可以创建一个变量,其类型为Contact,其名称我们称之为con

Contact con;

这是它内部的成员
2020-12-19
data是一个数组,上面提到过,该数组的每一个元素都是一个结构体类型
2020-12-19

三、通讯录界面

菜单可以实现与用户的良好交互,因此有必要实现一个菜单打印函数。


```c
void menu()
{
	printf("*******************************************************\n");
	printf("***********1、add                   2、del*************\n");
	printf("***********3、search                4、modify**********\n");
	printf("***********5、show                  6、sort************\n");
	printf("***********************0、exit*************************\n");
	printf("*******************************************************\n");
	
}

根据用户的输入,应该可以实现相应的功能,因此我们写出如下代码

int input;
	do
	{
		menu();
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			add();//增加功能
			break;
		case 2:
			del();//删除功能
			break;
		case 3:
			search();//查找功能
			break;
		case 4:
			modify();//更改功能
			break;
		case 5:
			show();//展示
			break;
		case 6:
			sort();//排序
			break;
		case 0:
			break;
		default:
			printf("你的输入有误,请重新输入\n");
			break;
		}
	} while (input);

当input输入为0时,while(input)判定为假,跳出循环。当用户输入0-6之外的数字,会给出“你的输入有误,请重新输入”的提示。
以上就是通讯录的界面部分

四、 通讯录的初始化

由于一开始,我们的通讯录内部是没有任何成员的,且size应置为0,即将第一个成员放入数组的第0个位置。因此,我们需要对通讯录进行初始化。
初始化前:
2020-12-19
初始化方法:创建一个Init函数进行实现

void Init(Contact* ps)
{
	memset(ps->data, 0, sizeof(ps->data));
	ps->size = 0;
}

这里借助内存设置函数memset将data这块空间的内存全部设为0。注意,由于我们要改变的是con的值,因此我们选择传址调用函数。
初始化后:
2020-12-19

五、功能实现

一、增加

增加函数,因为要改变通讯录的内部,因此依然选择传址调用

void add(Contact* con)

我们要做的依次输入成员信息,并将该信息存入data数组的相应位置。因此,每执行一次该函数,size就应该++一次。那么,如何访问到该数组呢?con->data可访问该数组,那么如何访问该数组的第size个元素呢? 可以使用 (con->data)[con->size]
那么如何访问第size个元素的某个变量,比如年龄呢?我们可以借助"."运算符来实现。 (con->data)[con->size].age接着我们借助scanf实现数据的输入

void add(Contact* con)
{
	printf("请输入住址\n");
	scanf("%s", &((con->data)[con->size].address));
	printf("请输入姓名\n");
	scanf("%s", &((con->data)[con->size].name));
	printf("请输入性别\n");
	scanf("%s", &((con->data)[con->size].sex));
	printf("请输入电话\n");
	scanf("%s", &((con->data)[con->size].tel));
	printf("请输入年龄\n");
	scanf("%d", &((con->data)[con->size].age));
	(con->size)++;
	printf("添加完成\n");
	
}

增加的实现效果如下
2020-12-19

依次输入后,通过监视窗口可以看到data[0]已经发生了改变。
2020-12-19

二、展示

展示窗口可以展示你目前的通讯录的内容,实现完该函数后对后续功能的检查会变得十分方便,因此我们先来实现 展示 这个功能。

void show(Contact* con)
{
	for (int i = 0; i < con->size; i++)
	{
		printf("-----------------------------\n");
		printf("    成员编号:【%d】\n", i);
		printf("姓名:%s\n", (con->data)[i].name);
		printf("年龄:%d\n", (con->data)[i].age);
		printf("电话:%s\n", (con->data)[i].tel);
		printf("住址:%s\n", (con->data)[i].address);
		printf("性别:%s\n", (con->data)[i].sex);

	}
	
}

这段代码的逻辑十分简单,通过一个for循环来确定打印的名单数目,即如果size为1,就只打印一个名单(因为此时只有一个成员)效果如下

2020-12-19
2020-12-19
可以看到,当我选择了’‘show’'时,其展示了我存入的两个成员的信息。

三、删除

删除功能,即删除某个成员的信息
这个功能就有些复杂了,第一,你要找到你所删除的元素的位置,比如我要删掉5号,那么我们就要找到对应数组的下标,并将其删除。第二,删除之后通讯录的状态如何把控。假设我们现在有八个成员,而我们要删掉第4个成员的信息,我们其实有两种删除方法
1、删掉四,随后五、六、七、八依次往前覆盖,并进行size–(因为现在只剩下七个元素了)
2、直接将八移动到四的位置。但这样会打乱通讯录成员的顺序。
我们在这里选择1进行实现。
首先,我们使用for循环找到要删除的元素的位置,如果循环到最后依然没有找到,就打印要找的人不存在并return.


```c
for ( i = 0; i < con->size; ++i)
	{
		if (strcmp((con->data)[i].name, del_name) == 0)
			break;
	}
	if (i == con->size)
	{
		printf("要删除的人不存在");
		return;
	}

接着,我们再次借助for循环,挨个进行元素替换,最后,我们进行con->size–并在屏幕上打印删除成功

else
{
      for (int m = i; m < con->size-1; m++)
	{
		(con->data)[i] = (con->data)[i + 1];
		(con->size)--;
	printf("删除成功");
	}
}

效果展示:
先存入三个成员
2020-12-19

然后输入一个不存在的成员

2020-12-19
然后我们删除李四
2020-12-19

删除实现成功!

四、查找

写过删除功能后,查找功能就似乎变得十分简单了;
查找功能虽不需要进行通讯录内部的改变,但众所周知,结构体传参传指针的效率远高于直接传入一个结构体,因此我们依然选择传入指针。
那么我们只需实现类似于删除中的查找姓名功能,再进行打印即可。
如果输入了一个不存在的姓名,会给出提示
2020-12-19
如果给出了一个存在的成员名字,会打印出该成员的信息

2020-12-19
代码逻辑十分简单,如下所示

void search(Contact* con)
{
	char search_name[10];
	printf("请输入你要查找的成员的名字\n");
	scanf("%s", &search_name);
	int i;
	for (i = 0; i < con->size; ++i)
	{
		if (strcmp((con->data)[i].name, search_name) == 0)
			break;
	}
	if (i == con->size)
	{
		printf("要查找的人不存在\n");
	}
	else
	{
		printf("     查找成功,成员信息如下\n    ");
		printf("-----------------------------\n");
		printf("    成员编号:【%d】\n", i);
		printf("姓名:%s\n", (con->data)[i].name);
		printf("年龄:%d\n", (con->data)[i].age);
		printf("电话:%s\n", (con->data)[i].tel);
		printf("住址:%s\n", (con->data)[i].address);
		printf("性别:%s\n", (con->data)[i].sex);
	}
	
}

五、修改

修改的逻辑也十分简单,输入需要修改的成员编号,然后重新输入数据即可
效果如下
先增添一名成员
2020-12-19

此时面板如下
2020-12-19
再修改0号成员
2020-12-19
修改完展示如下
2020-12-19

可以看到,0号成员的信息已经发生了改变
代码如下

void modify(Contact* con)
{
	printf("请输入你要修改的成员的编号\n");
	int number;
	scanf("%d", &number);
	printf("请输入新的住址\n");
	scanf("%s", &((con->data)[number].address));
	printf("请输入新的姓名\n");
	scanf("%s", &((con->data)[number].name));
	printf("请输入新的性别\n");
	scanf("%s", &((con->data)[number].sex));
	printf("请输入新的电话\n");
	scanf("%s", &((con->data)[number].tel));
	printf("请输入新的年龄\n");
	scanf("%d", &((con->data)[number].age));
	printf("修改完成\n");
}

六、排序

最后一个功能为排序功能,即输入你要交换的两个成员的编号,然后对他们的信息进行交换。
这个功能我们需要创建一个临时空间用于交换,因此我们在原有的Contact这个结构体类中新增一个成员

typedef struct Contact
{
	PeoInfo data2[20];
	PeoInfo data[1000];
	int size;
}Contact;

即data2,其用于临时储存
随后进行交换即可
交换前
2020-12-19
交换后

![在这里插入图片描述](https://www.icode9.com/i/ll/?i=20201220140450491.png?,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl81MjAxNjc4Mg==,size_16,color_FFFFFF,t_70)

代码

```c
void sort(Contact* con)
{
	printf("请输入你要交换的两个成员的编号(二者用空格隔开)\n");
	int num1;
	int num2;
	scanf("%d%d", &num1, &num2);
	(con->data2)[0] = (con->data)[num1];
	(con->data)[num1] = (con->data)[num2];
	(con->data)[num2] = (con->data2)[0];
	printf("交换成功\n");
}

六 功能优化

如果仔细观察,你会发现其实每次输一个功能是,这个通讯录的界面十分混乱。那么如何解决这个问题呢,可以在适当的位置加入cls,即清空屏幕来达到简洁的效果。
2020-12-19

我选择的是在除去菜单打印函数的每个函数的入口加入cls,这样每次执行一个新的功能,都会把残留的信息清空。

七 完整代码

头文件(用于函数的声明以及结构体的声明):contact.h

#ifndef _CONTACT_H_
#define _CONTACT_H_
#include<stdio.h>
#include<windows.h>
typedef struct PeoInfo
{
	char name[10];
	char sex[5];
	int age;
	char address[20];
	char tel[12];
}PeoInfo;
typedef struct Contact
{
	PeoInfo data2[20];
	PeoInfo data[1000];
	int size;
}Contact;
void menu();
void Init(Contact*);
void add(Contact*);
void show(Contact*);
void del(Contact*);
void searcg(Contact*);
void modify(Contact*);
void sort(Contact*);
#endif // _CONTACT_H_

源文件1(用于函数的实现):test.c

#include"contact.h"
void menu()
{
	printf("*******************************************************\n");
	printf("***********1、add                   2、del*************\n");
	printf("***********3、search                4、modify**********\n");
	printf("***********5、show                  6、sort************\n");
	printf("***********************0、exit*************************\n");
	printf("*******************************************************\n");
	
}
void Init(Contact* con)
{
	system("cls");
	memset(con->data, 0, sizeof(con->data));
	con->size = 0;
}
void add(Contact* con)
{
	system("cls");
	printf("请输入住址\n");
	scanf("%s", &((con->data)[con->size].address));
	printf("请输入姓名\n");
	scanf("%s", &((con->data)[con->size].name));
	printf("请输入性别\n");
	scanf("%s", &((con->data)[con->size].sex));
	printf("请输入电话\n");
	scanf("%s", &((con->data)[con->size].tel));
	printf("请输入年龄\n");
	scanf("%d", &((con->data)[con->size].age));
	(con->size)++;
	printf("添加完成\n");
}
void show(Contact* con)
{
	system("cls");
	if (con->size == 0)
	{
		printf("通讯录为空");
	}
	else
	{
		for (int i = 0; i < con->size; i++)
		{
			printf("-----------------------------\n");
			printf("    成员编号:【%d】\n", i);
			printf("姓名:%s\n", (con->data)[i].name);
			printf("年龄:%d\n", (con->data)[i].age);
			printf("电话:%s\n", (con->data)[i].tel);
			printf("住址:%s\n", (con->data)[i].address);
			printf("性别:%s\n", (con->data)[i].sex);
		}
	}
	
}
void del(Contact* con)
{
	system("cls");
	char del_name[10];
	printf("请输入你要删除的成员的名字\n");
	scanf("%s", &del_name);
	int i;
	for ( i = 0; i < con->size; ++i)
	{
		if (strcmp((con->data)[i].name, del_name) == 0)
			break;
	}
	if (i == con->size)
	{
		printf("要删除的人不存在\n");
	}
	else
	{
		for (int m = i; m < con->size - 1; m++)
		{
			(con->data)[i] = (con->data)[i + 1];
		}
		(con->size)--;
		printf("删除成功\n");
	}
}
void search(Contact* con)
{
	system("cls");
	char search_name[10];
	printf("请输入你要查找的成员的名字\n");
	scanf("%s", &search_name);
	int i;
	for (i = 0; i < con->size; ++i)
	{
		if (strcmp((con->data)[i].name, search_name) == 0)
			break;
	}
	if (i == con->size)
	{
		printf("要查找的人不存在\n");
	}
	else
	{
		printf("     查找成功,成员信息如下\n    ");
		printf("-----------------------------\n");
		printf("    成员编号:【%d】\n", i);
		printf("姓名:%s\n", (con->data)[i].name);
		printf("年龄:%d\n", (con->data)[i].age);
		printf("电话:%s\n", (con->data)[i].tel);
		printf("住址:%s\n", (con->data)[i].address);
		printf("性别:%s\n", (con->data)[i].sex);
	}
}
void modify(Contact* con)
{
	system("cls");
	printf("请输入你要修改的成员的编号\n");
	int number;
	scanf("%d", &number);
	printf("请输入新的住址\n");
	scanf("%s", &((con->data)[number].address));
	printf("请输入新的姓名\n");
	scanf("%s", &((con->data)[number].name));
	printf("请输入新的性别\n");
	scanf("%s", &((con->data)[number].sex));
	printf("请输入新的电话\n");
	scanf("%s", &((con->data)[number].tel));
	printf("请输入新的年龄\n");
	scanf("%d", &((con->data)[number].age));
	printf("修改完成\n");
}
void sort(Contact* con)
{
	system("cls");
	printf("请输入你要交换的两个成员的编号(二者用空格隔开)\n");
	int num1;
	int num2;
	scanf("%d%d", &num1, &num2);
	(con->data2)[0] = (con->data)[num1];
	(con->data)[num1] = (con->data)[num2];
	(con->data)[num2] = (con->data2)[0];
	printf("交换成功\n");
}

源文件2(调用函数):contact.c

#include"contact.h"
void main()
{
	Contact con;
	Init(&con);
	int input;
	do
	{
		
		menu();
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			add(&con);//增加功能

			break;
		case 2:
			del(&con);//删除功能
			break;
		case 3:
			search(&con);//查找功能
			break;
		case 4:
			modify(&con);//修改功能
			break;
		case 5:
			show(&con);//展示
			break;
		case 6:
			sort(&con);//排序
			break;
		case 0:
			break;
		default:
			printf("你的输入有误,请重新输入\n");
			break;
		}
	} while (input);	
}

总结

不得不说的是,这个通讯录的功能十分简陋,第一,它不允许你根据成员的多少来设置空间,而是固定的1000容量。第二,每当你关闭界面,你的所有成员信息都会被销毁,下次打开时什么也没有。这显然不能称之为一个合格的通讯录。在我的下篇博客我会对这两个问题进行解决,码字不易,希望点赞支持

上一篇:反相器


下一篇:WPF 后台模拟界面触摸点击