前言:
上期博客写了静态通讯录并且答应给大家写一个动态版,这不,它来了:
1.动态版与静态版的区别
静态版的内存空间开辟大小是固定的,放了预期的最大值,并不会根据实际存放的数据而变化;
当需要存放的数据较少时,难免会出现内存的浪费,所以我们考虑申请动态内存开辟;
2.相关函数的介绍
2.1 malloc
开辟动态内存,最经典的就是 malloc 函数了:
函数的作用是向内存申请一块连续可用的空间,并返回指向这块空间的指针;
用它需要传递一个无符号整型的参数:需要开辟的动态内存的大小,单位是字节;
如果开辟成功,函数返回指向开辟好空间的指针;
如果开辟失败,函数返回NULL指针;
因此 malloc 的返回值要做检查。
但是,动态内存嘛,向内存申请了还是要还的;
还内存也方便,用一个 free 函数就可以:
free 函数用来释放动态内存开辟的空间;
如果 ptr 指向的空间不是动态内存开辟的,free 函数的行为未定义;
如果 ptr 是 NULL,函数不作为;
另外注意,指针释放后小心变野哦,释放的指针要赋个 NULL;
开辟动态内存,养成好习惯:
free(ptr); ptr = NULL;
2.2 calloc
calloc 函数的作用也是申请动态内存,只不过比 malloc 更灵活些;
它为 num 个大小为 size 的元素开辟一块空间,
并且把空间的每个字节初始化为 0。
2.3 realloc
realloc 函数的出现让动态内存管理更加灵活;
realloc 函数的作用是调整动态开辟内存的大小;
函数返回调整之后的内存起始位置;
ptr 是要调整的内存地址;
size 是调整之后的新大小。
3.实现过程
做了以上铺垫,就可以开始正题了:
静态通讯录到动态通讯录,需要在哪动刀子呢?
多是在添加联系人信息时开辟动态内存:
我们先给存放联系人一个初始空间,再定义一个扩容空间,按需扩容。
给通讯录结构体改一 加一:
typedef struct Contact { PeoInform data[MAX];//存放的联系人 PeoInform* data;//指向存放人的信息空间 int sz;//当前已经存放的联系人个数 int capacity;//当前通讯录的容量 }Contact;
然后在原来的添加联系人的基础上加入检查是否扩容的函数:
void* check_capacity(Contact* pc) { assert(pc); if (pc->sz == pc->capacity) { printf("通讯录已满,无法添加\n"); return; } //扩容 PeoInform* ptr = (PeoInform*)realloc(pc->data, (pc->capacity + INC_SZ) * sizeof(PeoInform)); if (ptr == NULL) { perror("check_capacity"); return; } pc->data = ptr; pc->capacity += INC_SZ; printf("扩容成功\n"); }
初始化也要相应改变:
void Init_Contact(Contact* pc) { assert(pc); pc->sz = 0; PeoInform* ptr = (PeoInform*)calloc(DEFAULT_SZ, sizeof(PeoInform)); if (ptr == NULL) { perror("Init_Contact"); return; } pc->data = ptr; pc->capacity = DEFAULT_SZ; }
退出时要销毁通讯录:
void Dtroy_Contact(Contact* pc) { free(pc->data); pc->data = NULL; pc->capacity = 0; pc->sz = 0; pc = NULL; }
到这里基本上就可以了,已经化为动态版。
总结:
静态版升级为动态版,实际上只是在申请内存上做了改动,重点是学会如何使用动态内存开辟。