如果你没有看过通讯录初级,请先移步到那。
在前面我们写了一个静态的通讯录,通讯录的大小都是固定的,同时每次启动通讯录都需要重新输入数据。这用起来肯定是不人性化的。
进阶通讯录与原版的不同点就在于,通讯录的大小是会随着数据的添加而增大的,也就是动态内存管理,以及会对通讯录的数据进行存储,一旦通讯录被关闭数据就会自动存放在相应的文件。同时在下一次打开通讯录时,会自动将文件中的数据导入通讯录中。
1.对结构体contact的修改
//静态
//typedef struct contact
//{
// buddies data[MAX];
// int size;
//}contact;
//动态
typedef struct contact
{
buddies* data;
int size;
int capacity;
}contact;
capacity的添加是为了可以清楚的知道目前我们为通讯录开放的多大的空间。
2.对通讯录初始化的修改
//静态
//void InitContact(contact* pc)
//{
// memset(pc->data, 0, sizeof(pc->data));
// pc->size = 0;
//}
//动态
void InitContact(contact* pc)
{
pc->data = (buddies*)malloc(sizeof(buddies) * 2);
pc->size = 0;
pc->capacity = 2;
}
动态内存开辟,这里我们的规定是初始给2个联系人的空间,你可以自行修改。然后将malloc开辟空间是地址给pc->data
3.对通讯录添加数据的修改
//静态
//void AddContact(contact* pc)
//{
// if (pc->size > MAX)
// {
// printf("通讯录已满\n");
// return;
// }
// printf("请输入姓名:>");
// scanf("%s", pc->data[pc->size].name);
// printf("请输入年龄:>");
// scanf("%d", &pc->data[pc->size].age);
// printf("请输入性别:>");
// scanf("%s", pc->data[pc->size].sex);
// printf("请输入电话:>");
// scanf("%s", pc->data[pc->size].tel);
// printf("请输入地址:>");
// scanf("%s", pc->data[pc->size].add);
// printf("联系人添加完成\n");
// //添加成功,size要加1
// pc->size += 1;
//}
int check_capacity(contact* pc)//检查当前容量是否需要进行扩容
{
if (pc->size == pc->capacity)//扩容了
{
buddies* tmp = (buddies*)realloc(pc->data, sizeof(buddies) * (pc->capacity + 2));//利用realloc进行扩容,每次添加2个空间的大小,最佳扩容方法应该是每次扩大1.5倍~2倍。因为频繁的扩容容易造成内存碎片增多
if (tmp == NULL)
{
//扩容失败
perror("realloc");
return 0;
}
pc->data = tmp;
pc->capacity += 2;
printf("扩容成功\n");
return 1;
}
else//还没满
{
return 1;
}
}
//动态
void AddContact(contact* pc)
{
if (check_capacity(pc) == 0)
{
return;
}
printf("请输入姓名:>");
scanf("%s", pc->data[pc->size].name);
printf("请输入年龄:>");
scanf("%d", &pc->data[pc->size].age);
printf("请输入性别:>");
scanf("%s", pc->data[pc->size].sex);
printf("请输入电话:>");
scanf("%s", pc->data[pc->size].tel);
printf("请输入地址:>");
scanf("%s", pc->data[pc->size].add);
printf("联系人添加完成\n");
//添加成功,size要加1
pc->size += 1;
}
因为原版通讯录的大小是固定的,只需要检查空间是否满了就可以了。而动态的通讯录在检查后还需要进行扩容,扩容失败返回-1,没满返回1,扩容成功也返回1。AddContact函数再根据返回值来做下一步大操作。
3.通讯录的销毁
因为通讯录的空间是动态内存开辟的,所以再最后是需要还给存储系统的,我们需要释放空间。
至于什么时候释放,当用户退出程序时释放空间。
void DestoryContact(contact* pc)
{
free(pc->data);
pc->data = NULL;
pc->size = 0;
pc->capacity = 0;
}
int main()
{
int input = 0;
contact ct;
InitContact(&ct);
do
{
menu();//菜单
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case ADD:
AddContact(&