通讯录【C语言】【动态存储】


前言:
本期讲解的是如何实现通讯录的增、删、查、改四个功能,此次采用了分文件的方式进行书写,分别分为game.h、test.c和game.c,并且采用了动态开辟的方式进行数据的存储。

game.h

这部分内容主要包含的是通讯录结构体的定义,一些宏定义,比如存储名字的数组空间是多少,一个通讯录最初的存储容量是多少等等,以及一些函数的声明。

test.c

为了方便用户选择所使用的功能,可以设计一个switch的结构来进行实现,并且为了方便用户使用,我们可以在外层再加一个do while的循环,来帮助用户在选择完一个操作后可以继续选择是否进行下一个操作。中间我采用了枚举的方式进行书写,这样可以提高阅读者对代码的可读性。

#include"contact.h"
void menu()
{
    
    
	printf("************************************\n");
	printf("********* 1. Add    2. Del   *******\n");
	printf("********* 3. search 4.modify *******\n");
	printf("********* 5.print   0. exit  *******\n");
	printf("************************************\n");
}
enum
{
    
    
	EXIT,
	ADD,
	DEL,
	SREACH,
	MODIFY,
	PRINT
};
int main()
{
    
    
	int input = 0;
	// 创建通讯录
	Contact con;
	// 初始化通讯录
	InitContact(&con);
	do
	{
    
    
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
    
    
		case ADD:
			Addcontact(&con);
			break;
		case DEL:
			Delcontact(&con);
			break;
		case SREACH:
			Sreachcontact(&con);
			break;
		case MODIFY:
			Modifycontact(&con);
			break;
		case PRINT:
			print(&con);
			break;
		case EXIT:
			Destorycontact(&con);
			printf("退出通讯录\n");
			break;
		default:
			printf("输入错误,请重新输入\n");
		}
	} while (input);
	return 0;
}

game.c的实现

初始化通讯录

首先我们是先要开辟一块存放数据的空间,这里采用malloc进行,函数原型是 void *malloc( size_t size );括号里面是准备开辟多少字节的空间,这样就可以得到我们需要的空间了。perror是一个库函数,它的作用是去在屏幕上打出程序是因为什么原因出错的,而如果pc->date是空指针,说明开辟空间失败,从而perror就会报错。sz是表示目前存放了多少个信息,capacity是表示目前通讯录的最大容量。

void InitContact(Contact* pc)
{
    
    
	pc->date = (Peoinfo*)malloc(CAPA_MAX * sizeof(Peoinfo));
	if (pc->date == NULL)
	{
    
    
		perror("InitContact");
		return;
	}
	pc->sz = 0;
	pc->capacity = CAPA_MAX;
}

增加人员信息

对于增加人员信息,我们只需要依次输入某个人员的各个信息就可以了,再输入完毕时讲sz++,来表明通讯录内的人员增加了一个,但是一直在通讯录进行增加,如果一开始开辟的空间用完了呢?因此在每次增加人员信息之前,我们应该判断一下通讯录是否已经满了,如果满了就进行增容。增容的话我们采用realloc,它的函数原型是void *realloc( void *memblock, size_t size );括号里的参数第一个是原来开辟空间的首地址,第二个是你第二次需要开辟的空间大小,然后我们可以再将我们刚开始定义的capacity容量进行修改就可以了。

void Addcontact(Contact* pc)
{
    
    
	// 考虑增容
	if (pc->sz == pc->capacity)
	{
    
    
		Peoinfo* ptr = (Peoinfo*)realloc(pc->date, (pc->capacity + INC_SZ) * sizeof(Peoinfo));
		if (ptr != NULL)
		{
    
    
			pc->date = ptr;
			pc->capacity += INC_SZ;
			printf("增容成功\n");
		}
		else
		{
    
    
			perror("Addcontact");
			return;
		}
	}
	printf("请输入姓名:>");
	scanf("%s", pc->date[pc->sz].name);		
	printf("请输入性别:>");
	scanf("%s", pc->date[pc->sz].sex);
	printf("请输入年龄:>");
	scanf("%d", &pc->date[pc->sz].age);
	printf("请输入电话:>");
	scanf("%s", pc->date[pc->sz].tele);
	printf("请输入地址:>");
	scanf("%s", pc->date[pc->sz].addr);
	pc->sz++;
	printf("增加成功\n");
}

打印通讯录

进行依次打印就可以了,不过我们中间可以加上\t来让我们的数据进行分隔开,-10s的意思就是与下一个数据空出10格空间,这里就是姓名和性别中间空了十个格子,大家可以试着去掉这些再加上分别打印一下,体会一下这个效果。

void print(Contact* pc)
{
    
    
	// 打印标题
	printf("%-10s\t%-5s\t%s\t%-12s\t%-20s\n", "姓名", "性别", "年龄", "电话", "地址");
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
    
    
		printf("%-10s\t%-5s\t%d\t%-12s\t%-20s\n", pc->date[i].name,
			pc->date[i].sex,
			pc->date[i].age,
			pc->date[i].tele,
			pc->date[i].addr);
	}
}

查找人员

查找人的话我们只需要找到这个人的所在的下标就可以了,但是我们可以想一想,当删除某个人之前,我们是不是得先找到这个人,然后才能删除他,所以我们也可以把实现查找人员下标功能写成一个函数,也算是方便多次使用了。

static int Find(Contact* pc,char name[])
{
    
    
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
    
    
		if (strcmp(pc->date[i].name, name) == 0)
		{
    
    
			return i;
		}
	}
	return -1;
}
void Sreachcontact(Contact* pc)
{
    
    
	char name[NAME] = {
    
     0 };
	printf("请输入需要查找人员的名字:>");
	scanf("%s", name);
	int ret = Find(pc, name);
	if (ret == -1)
	{
    
    
		printf("人员不存在\n");
	}
	printf("%-10s\t%-5s\t%d\t%-12s\t%-20s\n", pc->date[ret].name,
			pc->date[ret].sex,
			pc->date[ret].age,
			pc->date[ret].tele,
			pc->date[ret].addr);
}

删除人员

删除人员就很简单了,我们只需要先找到他的下标,然后将他后面的人员信息一个一个往前覆盖,就可以完成删除了。但是在删除之前我们还需要判断一下通讯录是否为空,如果是空的话那就是没有人员信息,那我们还删除什么呢?请看代码:

void Delcontact(Contact* pc)
{
    
    
	if (pc->sz == 0)
	{
    
    
		printf("通讯录为空,无法删除\n");
		return;
	}
	char name[NAME] = {
    
     0 };
	printf("请输入需要删除人员的名字:>");
	scanf("%s", name);
	// 先找到所需要删除人员的下标
	int ret = Find(pc,name);
	if (ret == -1)
	{
    
    
		printf("人员不存在\n");
		return;
	}
	// 删除
	int i = 0;
	for (i = ret; i < pc->sz-1; i++)
	{
    
    
		pc->date[i] = pc->date[i + 1];
	}
	pc->sz--;
	printf("删除成功\n");
}

修改信息

同样的,在修改时我们先找到这个人信息所在的下标,然后直接重新输入我们想修改的信息就可以了。

void Modifycontact(Contact* pc)
{
    
    
	char name[NAME] = {
    
     0 };
	printf("请输入需要修改人员的名字:>");
	scanf("%s", name);
	int ret = Find(pc, name);
	if (ret == -1)
	{
    
    
		printf("人员不存在\n");
	}
	printf("请输入姓名:>");
	scanf("%s", pc->date[ret].name);
	printf("请输入性别:>");
	scanf("%s", pc->date[ret].sex);
	printf("请输入年龄:>");
	scanf("%d", &pc->date[ret].age);
	printf("请输入电话:>");
	scanf("%s", pc->date[ret].tele);
	printf("请输入地址:>");
	scanf("%s", pc->date[ret].addr);
	printf("修改成功\n");
}

销毁通讯录

因为我们采取的动态开辟的方法来进行的,所以在最后使用完之后需要将申请的空间进行释放,方式造成内存泄漏。

void Destorycontact(Contact* pc)
{
    
    
	free(pc->date);
	pc->date = NULL;
	pc->sz = 0;
	pc->capacity = 0;
}

在这里为大家奉上全部代码:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>

#define NAME 10
#define SEX  5
#define TELE 12
#define ADDR 20
#define CAPA_MAX 3
#define INC_SZ 2

//创建通讯录人员信息
typedef struct PeoInfo
{
    
    
	char name[NAME];
	char sex[SEX];
	int age;
	char tele[TELE];
	char addr[ADDR];
}Peoinfo;

typedef struct Contact
{
    
    
	Peoinfo* date;
	int sz;
	int capacity;
}Contact;
// 初始化通讯录
void InitContact(Contact* pc);

// 增加人员信息
void Addcontact(Contact* pc);

//打印通讯录信息
void print(Contact* pc);

// 删除信息
void Delcontact(Contact* pc);

// 查找信息
void Sreachcontact(Contact* pc);

// 修改信息
void Modifycontact(Contact* pc);

//销毁通讯录
void Destorycontact(Contact* pc);
#include"contact.h"
void menu()
{
    
    
	printf("************************************\n");
	printf("********* 1. Add    2. Del   *******\n");
	printf("********* 3. search 4.modify *******\n");
	printf("********* 5.print   0. exit  *******\n");
	printf("************************************\n");
}
enum
{
    
    
	EXIT,
	ADD,
	DEL,
	SREACH,
	MODIFY,
	PRINT
};
int main()
{
    
    
	int input = 0;
	// 创建通讯录
	Contact con;
	// 初始化通讯录
	InitContact(&con);
	do
	{
    
    
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
    
    
		case ADD:
			Addcontact(&con);
			break;
		case DEL:
			Delcontact(&con);
			break;
		case SREACH:
			Sreachcontact(&con);
			break;
		case MODIFY:
			Modifycontact(&con);
			break;
		case PRINT:
			print(&con);
			break;
		case EXIT:
			Destorycontact(&con);
			printf("退出通讯录\n");
			break;
		default:
			printf("输入错误,请重新输入\n");
		}
	} while (input);
	return 0;
}
#include"contact.h"

void InitContact(Contact* pc)
{
    
    
	pc->date = (Peoinfo*)malloc(CAPA_MAX * sizeof(Peoinfo));
	if (pc->date == NULL)
	{
    
    
		perror("InitContact");
		return;
	}
	pc->sz = 0;
	pc->capacity = CAPA_MAX;
}

void Addcontact(Contact* pc)
{
    
    
	// 考虑增容

	if (pc->sz == pc->capacity)
	{
    
    
		Peoinfo* ptr = (Peoinfo*)realloc(pc->date, (pc->capacity + INC_SZ) * sizeof(Peoinfo));
		if (ptr != NULL)
		{
    
    
			pc->date = ptr;
			pc->capacity += INC_SZ;
			printf("增容成功\n");
		}
		else
		{
    
    
			perror("Addcontact");
			return;
		}
	}

	printf("请输入姓名:>");
	scanf("%s", pc->date[pc->sz].name);		
	printf("请输入性别:>");
	scanf("%s", pc->date[pc->sz].sex);
	printf("请输入年龄:>");
	scanf("%d", &pc->date[pc->sz].age);
	printf("请输入电话:>");
	scanf("%s", pc->date[pc->sz].tele);
	printf("请输入地址:>");
	scanf("%s", pc->date[pc->sz].addr);
	pc->sz++;
	printf("增加成功\n");
	
}

void print(Contact* pc)
{
    
    
	// 打印标题
	printf("%-10s\t%-5s\t%s\t%-12s\t%-20s\n", "姓名", "性别", "年龄", "电话", "地址");
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
    
    
		printf("%-10s\t%-5s\t%d\t%-12s\t%-20s\n", pc->date[i].name,
			pc->date[i].sex,
			pc->date[i].age,
			pc->date[i].tele,
			pc->date[i].addr);
	}
}
static int Find(Contact* pc,char name[])
{
    
    
	int i = 0;
	for (i = 0; i < pc->sz; i++)
	{
    
    
		if (strcmp(pc->date[i].name, name) == 0)
		{
    
    
			return i;
		}
	}
	return -1;
}
void Delcontact(Contact* pc)
{
    
    
	if (pc->sz == 0)
	{
    
    
		printf("通讯录为空,无法删除\n");
		return;
	}
	char name[NAME] = {
    
     0 };
	printf("请输入需要删除人员的名字:>");
	scanf("%s", name);
	// 先找到所需要删除人员的下标
	int ret = Find(pc,name);
	if (ret == -1)
	{
    
    
		printf("人员不存在\n");
		return;
	}
	// 删除
	int i = 0;
	for (i = ret; i < pc->sz-1; i++)
	{
    
    
		pc->date[i] = pc->date[i + 1];
	}
	pc->sz--;
	printf("删除成功\n");
}

void Sreachcontact(Contact* pc)
{
    
    
	char name[NAME] = {
    
     0 };
	printf("请输入需要查找人员的名字:>");
	scanf("%s", name);
	int ret = Find(pc, name);
	if (ret == -1)
	{
    
    
		printf("人员不存在\n");

	}
	printf("%-10s\t%-5s\t%d\t%-12s\t%-20s\n", pc->date[ret].name,
			pc->date[ret].sex,
			pc->date[ret].age,
			pc->date[ret].tele,
			pc->date[ret].addr);
}

void Modifycontact(Contact* pc)
{
    
    
	char name[NAME] = {
    
     0 };
	printf("请输入需要修改人员的名字:>");
	scanf("%s", name);
	int ret = Find(pc, name);
	if (ret == -1)
	{
    
    
		printf("人员不存在\n");

	}
	printf("请输入姓名:>");
	scanf("%s", pc->date[ret].name);
	printf("请输入性别:>");
	scanf("%s", pc->date[ret].sex);
	printf("请输入年龄:>");
	scanf("%d", &pc->date[ret].age);
	printf("请输入电话:>");
	scanf("%s", pc->date[ret].tele);
	printf("请输入地址:>");
	scanf("%s", pc->date[ret].addr);
	printf("修改成功\n");
}

void Destorycontact(Contact* pc)
{
    
    
	free(pc->date);
	pc->date = NULL;
	pc->sz = 0;
	pc->capacity = 0;
}

总结

  • 好耶!!又双叒叕完成了一篇文章,希望能对大家有所帮助嗷!!如果觉得小生写的不错(嘴角上扬),可以动动您灵巧的小手点赞+收藏以示鼓励!!谢谢大家啦~~
    好耶!!这就滚去正常总结(被打):
  • 这个通讯录其实还没有完善,在这个基础上我们还可以去添加一些排序,比如按照名字、电话号什么什么的,以及用一些文件方面的知识,将我们每次继续的信息保存下来,这样在我们下一次打开通讯录的时候让上一次保存的信息依然存在,暂时就只能想到这么多力!!如果还有什么问题大家可以在评论区留言喔 ~ 撒悠啦啦

猜你喜欢

转载自blog.csdn.net/qq_62321047/article/details/129066419