引言:
我们在创建一个局部变量时,通过下列定义语句向内存申请空间,内存在栈区为变量开辟相应的空间。
int val=10;//在内存中栈区中开辟大小为4Byte大小的空间
char array[10]={0};//在内存中栈区中开辟大小为10Byte大小的连续的空间
...
上述方式开辟空间的特点:
- 空间开辟大小是固定的,开辟好后空间大小不能再修改。
- 灵活性差,以数组开辟空间为例,必须明确给出数组大小,开辟好后大小固定,不能依据元素个数对空间大小做出修改。
因此,基于这种静态的开辟内存空间的方式,今天想向大家介绍一种灵活的动态申请内存空间的方式--通过动态内存函数实现。
动态内存函数介绍:
1.malloc()
功能:Allocates memory blocks.
这个函数用于向内存申请一块连续可用的空间。并返回指向这块空间的指针。
- 如果开辟成功,返回指向这块空间的指针。
- 开辟失败返回空指针NULL,因此调用该函数后需要进行检查是否成功申请空间。
参数:参数是size_t(无符号整数)类型的数,表示申请内存空间的大小。
e.g:
申请4个int大小的内存空间---malloc(sizeof(int)*4)
申请10个char大小的内存空间--malloc(sizeof(char)*10)
返回值:返回类型是void*,指向所申请的内存空间的地址,可以使用强制类型转换修改指针类型。
e.g:
int* p=(int*)malloc(sizeof(int)*4)
申请4个int大小的连续的内存空间,并让int*类型的指针p指向这块连续空间。
特别注意:
参数为0,malloc(0)的行为是标准是未定义的,取决于编译器。
2.realloc()
功能:Reallocate memory blocks.
用于调整已经动态申请的内存空间的大小。在使用malloc()函数动态申请内存空间后,如果我们发现过去申请的空间太小/大了,想要修改空间大小,就可以使用realloc()函数。
参数:realloc()函数有两个参数,分别为void*类型和size_t类型。
- memblock参数表示要调整的内存空间的地址,void*表示此处可以放任意类型的指针,根据内存空间中存放数据的数据类型填写该指针类型。
- size表示调整之后新的内存空间的大小。
返回值:调整之后的内存的起始地址。
注意:
realloc()函数的调整存在两种情况:
- 想要调整为比原来更大的空间时:
- 原空间后有足够大的空间:直接在原空间后进行扩容即可。
- 原空间后没有足够大的空间:在内存空间中重新找一个能满足要求的连续空间块来使用,并且系统会自动把原来数据拷贝到这块新的空间中。此时返回的指针值并非原来的内存空间地址,而是一个新的内存空间地址,因此注意realloc()函数的使用,最好不要直接用原内存块指针接受realloc()函数返回值结果,如果realloc()失败,返回NULL,会导致原空间不能再使用但也没被回收而导致内存泄漏。
tips:
如果realloc()函数中memblock参数是空指针,则相当于malloc()函数。
3.free()
功能:Deallocates or frees a memory block.
专门用于动态内存的释放和回收。
参数:要释放内存空间的地址。
返回值:无返回值。
4.calloc()
功能:Allocates an array in memory with elements initialized to 0.
在内存中开辟有num个元素的数组,每个元素大小为size字节,并把每个字节初始化为0。
参数:开辟num个大小为size字节的内存空间。
返回值:返回类型是void*,指向所申请的内存空间的地址,可以使用强制类型转换修改指针类型。
动态内存函数应用--通讯录管理系统
应用描述:
使用动态内存管理实现通讯录管理系统
应具备的功能有:
- 动态申请空间存储联系人信息(姓名、电话、地址)
- 添加联系人
- 删除联系人
- 查询联系人
- 修改联系人信息
- 显示系统中全部的联系人信息
- 销毁通信录系统
- 联系人信息结构体定义
typedef struct ContactNode
{
char name[20];
char tel[20];
char addr[20];
}connode;
2.通讯录结构体定义
typedef struct Contact
{
connode* pnode;
int size;//通讯录当前存储联系人信息的数量
int capacity;//通讯录容量
}con;
3.通讯录可以进行的操作
//通讯录初始化
void CONInit(con* con);
//添加联系人
void CONInsert(con* con);
//删除指定联系人
void CONRemove(con* con);
//查找指定联系人
void CONFind(con* con);
//修改指定联系人信息
void CONModify(con* con);
//显示通讯录中所有联系人
void CONShowall(con* con);
//通讯录销毁
void CONDestroy(con* con);
//通讯录扩容
void CONExpand(con* con);
4.通讯录操作
4.1通讯录初始化
void CONInit(con* con)
{
assert(con);//需要包含头文件<assert.h>
con->pnode = NULL;
con->size = 0;
con->capacity=0;
}
4.2通讯录扩容--动态申请空间
void CONExpand(con* con)
{
int newcapacity = (con->capacity == 0) ? 4 : (con->capacity * 2);//三目表达式设置通讯录的初始容量为4
connode* temp = realloc(con->pnode, sizeof(connode) * newcapacity);
if (temp == NULL)
{
printf("扩容失败\n");
return;
}
con->pnode = temp;
con->capacity = newcapacity;
}
4.3增加联系人
void CONInsert(con* con)
{
if (check_expand(con))//对通讯录容量检查,若满则扩容
{
CONExpand(con);
}
printf("请输入联系人姓名:\n");
scanf("%s", con->pnode[con->size].name);
printf("请输入联系人电话:\n");
scanf("%s", con->pnode[con->size].tel);
printf("请输入联系人地址:\n");
scanf("%s", con->pnode[con->size].addr);
con->size++;
printf("添加成功\n");
}
bool check_expand(con* con)//C语言中使用bool类型需要包含<stdbool.h>头文件
{
if (con->size == con->capacity)
return true;
else
return false;
}
4.4删除联系人
void CONRemove(con* con)
{
assert(con);
assert(con->pnode);
if(con->size==0)
{
printf("通讯录已为空,无需删除\n");
return;
}
printf("请输入要删除联系人的姓名:\n");
char Name[20] = { 0 };
scanf("%s", Name);
int i = 0;
int pos = -1;
for (i = 0; i < con->size; i++)
{
if (strcmp(con->pnode[i].name, Name) == 0)
{
pos = i;
break;
}
}
if (pos == -1)
{
printf("要删除的联系人不存在,请重新输入\n");
return;
}
for (i = pos; i < con->size - 1; i++)
{
con->pnode[i] = con->pnode[i + 1];
}
printf("删除成功\n");
con->size--;
}
4.5显示通讯录中的所有联系人
void CONShowall(con* con)
{
assert(con);
if (con->size == 0)
{
printf("通讯录为空\n");
return;
}
int i = 0;
printf("%-10s %-10s %-10s\n", "姓名:", "电话:", "地址:");//左对齐,占10位
for (i = 0; i < con->size; i++)
{
printf("%-10s %-10s %-10s\n", con->pnode[i].name, con->pnode[i].tel, con->pnode[i].addr);
}
}
4.6查找联系人
void CONFind(con* con)
{
assert(con);
assert(con->pnode);
printf("请输入要查找联系人的姓名:\n");
char Name[20] = { 0 };
scanf("%s", Name);
int pos = -1;
int i = 0;
for (i = 0; i < con->size; i++)
{
if (strcmp(con->pnode[i].name, Name) == 0)
{
pos = i;
break;
}
}if (pos == -1)
{
printf("要查找的联系人不存在,请重新输入\n");
return;
}
printf("%-10s %-10s %-10s\n", "姓名:", "电话:", "地址:");
printf("%-10s %-10s %-10s\n", con->pnode[pos].name, con->pnode[pos].tel, con->pnode[pos].addr);
printf("查找成功\n");
}
4.7修改联系人信息
void CONModify(con* con)
{
assert(con);
assert(con->pnode);
printf("请输入要修改联系人的姓名:\n");
char Name[20] = { 0 };
scanf("%s", Name);
int pos = -1;
int i = 0;
for (i = 0; i < con->size; i++)
{
if (strcmp(con->pnode[i].name, Name) == 0)
{
pos = i;
break;
}
}if (pos == -1)
{
printf("要修改的联系人不存在,请重新输入\n");
return;
}
printf("Modify information input:->\n");
printf("请输入联系人姓名:\n");
scanf("%s", con->pnode[pos].name);
printf("请输入联系人电话:\n");
scanf("%s", con->pnode[pos].tel);
printf("请输入联系人地址:\n");
scanf("%s", con->pnode[pos].addr);
printf("修改成功!\n");
}
4.8 通讯录销毁
void CONDestroy(con* con)
{
assert(con);
free(con->pnode);//使用free()函数释放动态申请的内存空间
con->pnode = NULL;
con->capacity = 0;
con->size = 0;
}
TEST.C
void test1()/在main()函数中测试
{
con con1;
CONInit(&con1);
CONInsert(&con1);
CONInsert(&con1);
CONInsert(&con1);
CONInsert(&con1);
CONInsert(&con1);
CONInsert(&con1);
CONShowall(&con1);
CONRemove(&con1);
CONRemove(&con1);
CONShowall(&con1);
CONInsert(&con1);
CONInsert(&con1);
CONInsert(&con1);
CONFind(&con1);
CONModify(&con1);
CONModify(&con1);
CONModify(&con1);
CONShowall(&con1);
CONDestroy(&con1);
}
本篇向大家介绍了动态内存函数,以及动态内存函数的应用--通讯录管理系统。如果文章有错误或不恰当之处欢迎在评论区留言或者私信小Q,如果觉得文章不错的话希望给个一键三连^-^,激励小Q写出更好的博客。希望本篇文章对您有帮助,我们下期再见!
标签:con1,--,联系人,pnode,通讯录,动态内存,printf,con From: https://blog.51cto.com/u_16191221/7862872