本文主要介绍通讯录的动态实现,静态版可见此文——>静态通讯录,文章主要介绍了两次实现的不同,以及涉及到的基本知识。希望可以帮助到大家。
一、动态内存函数
1、申请函数
a、 malloc
笔者认为,malloc即memory allocate,也就是内存分配;
功能
void* malloc (size_t size); malloc会在栈区申请一片连续空间,若申请成功并返回一个指向这边地址的指针,若失败则会返回NULL;
使用
由于申请失败会返回NULL,故每次malloc后,都需要判断是否申请成功; 返回指针是无类型的,故在使用malloc时,需自己指定类型,此处采用无类型,也是为了保证malloc可以适用于任何类型的对象; 申请空间size即便是0,malloc依旧会返回一个申请空间为0的地址,只不过这个地址不可以正常使用;
b、calloc
笔者认为,calloc,即clean memory allocate;直译就是干净的内存分配,也就是说,calloc会将申请到的空间初始化,使其变得clean; void* calloc(size_t num, size_t size);
功能
相比malloc,calloc的参数不同,作用也有些许差别,calloc会申请一篇空间为num个size字节大小的空间,若成功返回指向这片地址起始位置的指针,若失败也返回NULL;
使用
calloc相比malloc,
- 最大的差别便是calloc会将申请的内存初始化为0;
- 其次便是参数略有不同,malloc会申请size字节的空间,其参数size指的是申请空间的size; 而calloc会申请num*size字节的空间,其num指的是元素的个数,size指的是每个元素的大小;
- 其余使用同malloc;
2、释放函数free
free即空闲,笔者认为,将原本的内存空闲掉,也就是释放内存; void free( void* memblock );
功能
free会memblock指向的内存进行释放;
使用
- free中的参数memblock可以是NULL,但此时函数立马返回,什么都不发生;
- 否则,memblock必须时动态申请内存的起始地址,这样才可以将memblock指向的申请空间进行释放,否则函数会报错;
- 需要注意的是,若需要减少原本分配的内存,也不可采用如下方法: 使用free,而将memblock往后移。 memblock只能是动态内存的起始地址,否则free会报错;若要调整空间,可以使用接下来介绍的realloc;
3、调整函数realloc
在英语中,re-词根常有一再、重新的意思,笔者认为此处便是采用re词根意思,实际上,realloc也可以理解成reallocate,重新分配的意思; void* realloc(void* memblock, size_t size)
功能
- realloc会将memblock指向的内存重新分配为size大小,若申请成功,则会返回指向这片空间的指针,否则会返回NULL;
- 若申请的空间为0,同样会返回NULL,此时函数功能同free,会将memblock指向的动态内存进行释放;
- 若memblock为NULL,则函数功能同malloc;
使用
- 使用realloc时,其中的参数memblock,除NULL之外,必须是动态申请空间的起始位置;
- realloc在申请内存时,若为增大空间,而原memblock申请的空间后已没有足够的空间,则,malloc会在内存中寻找新的size字节大小的空间,并将原数据迁移到新空间,并返回指向这边空间的地址;
- 其余使用同malloc。
二、应用实例——通讯录的调整
静态实现版在此文中已有介绍——>静态通讯录,此处主要引入动态内存的使用,从而产生的修改——增加,删除,初始化,以及增加的退出,其余功能的实现与静态版相同。
1、结构体的修改
个人的结构体不用修改,而联系表的则有原本的数组,换成指针;另外增加一个参数用来确定当前容量的大小,具体原因见下方函数修改;
////联系表结构体静态版
//typedef struct Contact
//{
// Peo data[MAX];
// int sz;
//}Contact;
//联系表结构体
typedef struct Contact
{
Peo* data;
int sz;
int capacity;//容量
}Contact;
2、函数的修改
a、初始化
在静态版本中,初始化借用memset将数组中每个元素都初始化为0; 而此处实现动态的增加,则需要申请新的空间,随之便有一个问题: 申请多少?什么时候申请呢? 由此我们定义一个参数容量,capacity,当联系表中个数sz等于容量capacity时,扩容; 初始化,我们申请3个空间,之后每次扩容增加2个;
//初始化动态
//初始为3,后续每次增加2
void Init_Contact(Contact* con)
{
assert(con);
con->sz = 0;
con->capacity = 3;
con->data = (Peo*)malloc(sizeof(Peo) * con->capacity);
}
//扩容
void Enlarge(Contact* con)
{
con->capacity += 2;
Peo* tmp = NULL;
tmp = (Peo*)realloc(con->data, sizeof(con->capacity));
if (tmp != NULL)
{
con->data = tmp;
printf("扩容成功\n");
}
else
printf("扩容失败\n");
}
b、增加联系人
借助扩容,原本用于判断数组是否满的语句,现在只需扩容即可;
//增加联系人动态
void Add_Contact(Contact* con)
{
assert(con);
if (con->sz == con->capacity)
{
//扩容
Enlarge(con);
}
printf("请输入名字:");
scanf("%s", con->data[con->sz].name);
printf("请输入性别:");
scanf("%s", con->data[con->sz].sex);
printf("请输入年龄:");
scanf("%d", &(con->data[con->sz].age));
printf("请输入电话:");
scanf("%s", con->data[con->sz].tel);
printf("请输入地址:");
scanf("%s", con->data[con->sz].addr);
con->sz++;
printf("添加成功!\n");
}
c、删除联系人
相比静态,删除后,增加判断语句,是否容量比个数多2个,若多,则减少容量,调整分配空间;
//按名字删除动态
void Del_By_Name(Contact* con)
{
assert(con);
if (con->sz == 0)
{
printf("通讯录为空!不可删除\n");
return;
}
char cmp[20] = { 0 };
printf("请输入要删除的人:");
scanf("%s", cmp);
int x = Search_By_Name(con, cmp);
if (x != -1)
{
for (; x < con->sz; x++)
{
con->data[x] = con->data[x + 1];
}
con->sz--;
printf("删除成功!\n");
if (con->capacity - con->sz == 2)
{
con->capacity -= 2;
con->data = (Peo*)realloc(con->data, con->capacity);
}
}
else
{
printf("要删除的人不存在!\n");
}
}
d、增加删除语句
此处增加的删除语句,主要用来释放申请的空间,避免内存泄漏;
void Exit(Contact* con)
{
free(con->data);
con->data = NULL;
con->capacity = 0;
con->sz = 0;
}
汇总的代码以上传到gitee,有需要的话,可以点链接直达——>通讯录代码。
标签:sz,malloc,管理,memblock,通讯录,动态内存,con,data,size From: https://blog.51cto.com/u_15423682/6132764