在低版本中,我们使用固定长度的数组存放通讯录信息,但是数据信息过多就会出现越界错误,如果数据信息过少,又会造成极大的内存浪费,故我们可以采用动态内存开辟来很好地解决。
我们首先需要改变初始化函数,先利用malloc开辟一定的空间。
void initContact(struct Contact* connect)
{
assert(connect);
connect->size = 0;
connect->capacity = FAULT_SZ;
connect->data= (struct PeoInfo*)malloc(FAULT_SZ * sizeof(struct PeoInfo));
memset(connect->data, 0, sizeof(struct PeoInfo) * connect->capacity);
}
接下来在添加元素时,可能会出现空间不足的情况,所以我们首先应该判断size是否等于capacity,如果容量不足,我们就需要利用realloc函数进行扩容。
int check_is_full( struct Contact* connect)
{
if (connect->size == connect->capacity)
{
struct PeoInfo* p = (struct PeoInfo*)realloc(connect->data, (connect->capacity+EXPAND_SZ) * sizeof(struct PeoInfo));
if (p != NULL)
{
connect->data = p;
connect->capacity += EXPAND_SZ;
printf("扩容成功!\n");
p = NULL;
return 1;
}
else
{
printf("扩容失败,无法再继续添加!");
return 0;
}
}
else
{
return 1;
}
}
那么,我们添加元素的函数就会变成如下所示:
void addContact(struct Contact* connect)
{
assert(connect);
int flag = check_is_full(connect);
if (flag)
{
printf("姓名:");
scanf("%s", connect->data[connect->size].name);
printf("性别:");
scanf("%s", connect->data[connect->size].sex);
printf("年龄:");
scanf("%d", &(connect->data[connect->size].age));
printf("电话号码:");
scanf("%s", connect->data[connect->size].tele);
printf("地址:");
scanf("%s", connect->data[connect->size].adder);
connect->size++;
printf("添加成功!\n");
}
else
{
return;
}
}
但是在退出程序时,我们需要对开辟的内存进行释放,那么我们就需要再增加一个函数来释放空间。
void destoryContact(struct Contact* connect)
{
free(connect->data);
connect->data = NULL;
connect->capacity = 0;
connect->size = 0;
}
我们通常使用的通讯录是能够保存信息的,这时就需要在函数退出时,并将信息保存到一个文件上。
void saveContact(struct Contact* connect)
{
FILE* fpw =fopen("contact.txt", "wb");
if (fpw == NULL)
{
perror("fopen");
return;
}
for (int i = 0; i < connect->size; i++)
{
fwrite(connect->data + i, sizeof(struct PeoInfo), 1, fpw);
}
//fwrite(connect->data, sizeof(struct PeoInfo), connect->size, fpw);
//这样写也没问题
fclose(fpw);
fpw = NULL;
}
那么在进行初始化的时候,我们就应该将存储到文件的通讯录信息初始到Contact对象中去,以便能更好地进行排序、删除、查找等操作。 并且在这个函数中我们还需要调用是否需要扩容的那个函数。
void loadContact(struct Contact* connect)
{
FILE* fpr = fopen("contact.txt", "rb");
if (fpr == NULL)
{
perror("fopen");
return;
}
struct PeoInfo temp = { 0 };
while (fread(&temp, sizeof(struct PeoInfo), 1, fpr))
{
check_is_full(connect);
connect->data[connect->size] = temp;
connect->size++;
}
fclose(fpr);
fpr = NULL;
}
那么,初始化函数就会变为:
void initContact(struct Contact* connect)
{
assert(connect);
connect->size = 0;
connect->capacity = FAULT_SZ;
connect->data= (struct PeoInfo*)malloc(FAULT_SZ * sizeof(struct PeoInfo));
memset(connect->data, 0, sizeof(struct PeoInfo) * connect->capacity);
loadContact(connect);
}
这样我们的信息就会保存在文件中去了。
在升级版通讯录中,我们其余函数是保持不变的,我们的主函数做了略微修改:
#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
enum Option
{
quit,
add,
delete,
search,
modify,
sort,
list,
empty
};
void menu()
{
printf("--------------------------------------------------------------------\n");
printf("-----------1.add 2.delete--------------------------\n");
printf("-----------3.search 4.modify--------------------------\n");
printf("-----------5.sort 6.list----------------------------\n");
printf("-----------7.empty 0.exit----------------------------\n");
printf("--------------------------------------------------------------------\n");
}
int main()
{
enum Option option;
struct Contact connect;
initContact(&connect);
do
{
menu();
printf("请输入您要进行的操作:");
scanf("%d", &option);
switch (option)
{
case add:
addContact(&connect);
break;
case delete:
deleteContact(&connect);
break;
case search:
searchContact(&connect);
break;
case modify:
modifyContact(&connect);
break;
case sort:
sortContact(&connect);
break;
case list:
listContact(&connect);
break;
case empty:
emptyContact(&connect);
break;
case quit:
saveContact(&connect);
destoryContact(&connect);
printf("保存成功!\n");
printf("退出成功!\n");
break;
default:
printf("您的输入有误!");
break;
}
} while (option);
return 0;
}
注意在contact.h进行函数声明的更新!