在上一篇博客中讲完了动态内存分配,这时候我们就可以改进之前写的通讯录了,可以将其升级为动态内存的版本,既不用担心联系人满了,也不用担心内存浪费太大。
要将其改为动态版本主要是两件事,首先初始化的时候我们要动态开辟data的空间,光动态开辟还不够,我们还要增加一个变量来记录当前联系人列表的大小,空间使用完之后要记得释放。其次,我们要控制动态内存增长,就是当联系人的数量与联系人列表的大小相等时,我们要对data扩容。
知道了思路,实现起来就很简单了。首先我们将联系人列表初始化一定的空间,假设我们设定初始最大联系人数量为3,我们可以在头文件中用#define来定义,方便后续修改.与此同时,我们也可以用#define来定义每次扩容的空间。同时对结构体增加一个变量size记录当前最大可容纳联系人数量。
#define INIT_SIZE 3
#define ADD_SIZE 2
typedef struct Contact
{
People* data;
size_t count;
size_t size;
}Contact;
然后原来初始化通讯录的代码进行修改。
//动态版本初始化通讯录
void Init_Contact(Contact* pc)
{
assert(pc);
pc->data = (People*)malloc(sizeof(People) * INIT_SIZE);
pc->size = INIT_SIZE;
if (pc->data == NULL)
{
perror("malloc fail");
exit(-1);
}
int i = 0;
for (i = 0; i < pc->size; i++)
{
*((pc->data[i]).name) = 0;
(pc->data[i]).age = 0;
*((pc->data[i]).sex) = 0;
*((pc->data[i]).tele) = 0;
*((pc->data[i]).address) = 0;
}
pc->count = 0;
}
当我们使用动态内存来实现通讯录时,为了方便释放内存,我们再写一个函数用来释放,在退出通讯录之前使用这个函数进行内存释放。
void Destroy_Contact(Contact* pc)
{
assert(pc);
free(pc->data);
pc->data = NULL;
pc->size = 0;
pc->count = 0;
}
接下来就要考虑增容的问题了,增容只会在Add中出现,我们将增容操作与判断size和count的关系写在一个函数Check里,每次进入Add函数之后,都要先使用一次Check函数来判断是否需要增容。
void Check(Contact* pc)
{
assert(pc);
if (pc->count == pc->size)//增容
{
People* ptr = (People*)realloc(pc->data,sizeof(People) * (pc->size + ADD_SIZE));
if (ptr == NULL)
{
perror("realloc fail");
exit(-1);
}
pc->data = ptr;
}
}
再对之前的一些小细节进行一些小修改,就能实现动态版本了。