一、使用动态开辟内存
在低版本中,我们使用固定长度的数组存放通讯录信息,但是数据信息过多就会出现越界错误,如果数据信息过少,又会造成极大的内存浪费,故我们可以采用动态内存开辟来很好地解决。
我们首先需要改变初始化函数,先利用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; }