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

目录

一.前言

二.为什么要动态存储?

1.动态存储的作用:

2动态与静态存储的区别:

三.动态存储的实现

1.通讯录容量

2.初始化通讯录

3.增加/减少通讯录成员

增加通讯录成员

判断及实现扩容函数的实现

减少通讯录成员

判断及实现减容函数的实现

4.重置通讯录

5.退出通讯录

 四.结语


一.前言

本文在前文通讯录源码(链接:https://blog.csdn.net/qq_74641564/article/details/128741939)的基础上进行优化,以实现通讯录成员的动态存储。

二.为什么要动态存储?

1.动态存储的作用:

动态存储能实现对内存资源更合理的分配与使用

2动态与静态存储的区别:

静态版本中的数据没有动态版本方便灵活的分配内存。

拿静态通讯录来举例的话就很显而易见,假如一个静态通讯录需要存储100个人甚至1000个人的信息,那么提前创建的这些人的数据加起来将会极大的占据内存空间,甚至溢出,然而,如果有几个人就存几个人的数据,那么不就可以避免对内存浪费的情况了吗?

三.动态存储的实现

1.通讯录容量

将原来的成员结构体数组删除,取而代之的是成员结构体指针,同时需要创建一个新的变量来表示每次扩容减容的数量。

typedef struct Contact
{
	ContactMember* data;
	int sz;
	int capacity;
}Contact;

2.初始化通讯录

使用calloc函数申请了一定数量的成员结构体大小的空间,此处创建ptr以防返回NULL指针。

//初始化成员信息
//DEFAULT_SIZE定义为常量
void InitContact(Contact* con)
{
	assert(con);
	con->sz = 0;

    //申请空间
	ContactMember* ptr = (ContactMember*)calloc(DEFAULT_SIZE , sizeof(ContactMember));
	if (ptr == NULL)
	{
		perror("InitContact::calloc");
		return;
	}
	con->data = ptr;

	con->capacity = DEFAULT_SIZE;
}

3.增加/减少通讯录成员

增加通讯录成员

如果前面所申请的空间被使用完的话,那么就需要对原本申请的空间扩容,以此来存放更多的成员数据,因此在增加通讯录成员前对当前容量进行判断是否需要扩容。

void AddContact(Contact* con)
{
	assert(con);

    //检查扩容
	check_capacity(con);

	printf("请输入姓名:");
	scanf("%s", con->data[con->sz].Name);
	printf("请输入性别:");
	scanf("%s", con->data[con->sz].Sex);
	printf("请输入年龄:");
	scanf("%d", &con->data[con->sz].Age);
	printf("请输入住址:");
	scanf("%s", con->data[con->sz].Address);
	printf("请输入号码:");
	scanf("%s", con->data[con->sz].Number);
	printf("输入完毕!\n");

	con->sz++;
}

判断及实现扩容函数的实现

使用realloc函数对原本的容量扩大,同样,也要对返回的指针进行判断。要是直接返回NULL指针可就要出大问题呢...

//检查增容
void check_capacity(Contact* con)
{
	if (con->sz == con->capacity)
	{
		ContactMember* ptr = (ContactMember*)realloc(con->data, (con->capacity + Capacity) * sizeof(ContactMember));
		if (ptr == NULL)
		{
			perror("check_capacity::realloc");
			return;
		}
		con->data = ptr;
		con->capacity += Capacity;
		printf("扩容成功!\n");
	}
}

减少通讯录成员

与增加相似,但需要在减少成员之后再嵌套判断函数。

void DelContact(Contact* con)
{
	assert(con);

	if (con->sz == 0)
	{
		printf("没有可以删除的目标!\n");
		return;
	}

	printf("请输入目标删除人:");
	char name[NAME_MAX];
	scanf("%s", name);
	int ret = FindName(con, name);
	if (ret == -1)
	{
		printf("目标人物不存在!\n");
		return;
	}
	memmove(con->data + ret, con->data + ret + 1, sizeof(con->data[0]) * (con->sz - ret - 1));
	printf("删除成功!\n");
	con->sz--;

    //判断减容
	check_del_capacity(con);
}

判断及实现减容函数的实现

与增容函数一样,改变的只有加减号。

//检查减容
void check_del_capacity(Contact* con)
{
	if (con->sz <= con->capacity - Capacity && con->capacity >= DEFAULT_SIZE)
	{
		ContactMember* ptr = (ContactMember*)realloc(con->data, (con->capacity - Capacity) * sizeof(ContactMember));
		if (ptr == NULL)
		{
			perror("check_del_capacity::realloc");
			return;
		}
		con->data = ptr;
		con->capacity -= Capacity;
		printf("减容成功!\n");
	}
}

4.重置通讯录

俗话说,东西有借有还,既然前面申请了一定的空间,那么不需要用的时候就要还回去。重置的时候就要把前面申请的内存都给free(释放)掉,再重新申请原本大小的空间。当然,realloc函数也可以实现,任君选择。

void EmptyContact(Contact* con)
{
	assert(con);

	//释放前者内存
	free(con->data);
	con->data = NULL;

    //重置
	con->sz = 0;
	ContactMember* ptr = (ContactMember*)calloc(DEFAULT_SIZE, sizeof(ContactMember));
	if (ptr == NULL)
	{
		perror("InitContact::calloc");
		return;
	}
	con->data = ptr;
	con->capacity = DEFAULT_SIZE;

	printf("重置成功!\n");
}

5.退出通讯录

退出通讯录不能使用重置通讯录的函数,因为这会再申请一块空间,我们只需要将内存还回去就行了。

//退出通讯录
void DestoryContact(Contact* con)
{
	con->capacity = 0;
	con->sz = 0;
	free(con->data);
	con->data = NULL;
	con = NULL;
}

 四.结语

最后大家别忘了把修改的数据替换哦,让我们一起努力学习向心仪的offer进发把!

猜你喜欢

转载自blog.csdn.net/qq_74641564/article/details/128844827
今日推荐