动态内存管理函数及应用--通讯录管理系统(1)
  viMOS5Jem2go 2023年11月02日 59 0

引言:


我们在创建一个局部变量时,通过下列定义语句向内存申请空间,内存在栈区为变量开辟相应的空间。


int val=10;//在内存中栈区中开辟大小为4Byte大小的空间

char array[10]={0};//在内存中栈区中开辟大小为10Byte大小的连续的空间

...

上述方式开辟空间的特点:

  • 空间开辟大小是固定的,开辟好后空间大小不能再修改。
  • 灵活性差,以数组开辟空间为例,必须明确给出数组大小,开辟好后大小固定,不能依据元素个数对空间大小做出修改。

因此,基于这种静态的开辟内存空间的方式,今天想向大家介绍一种灵活的动态申请内存空间的方式--通过动态内存函数实现。


动态内存函数介绍:

1.malloc()

动态内存管理函数及应用--通讯录管理系统(1)_动态内存

功能: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()

动态内存管理函数及应用--通讯录管理系统(1)_free_02

功能:Reallocate memory blocks.

   用于调整已经动态申请的内存空间的大小。在使用malloc()函数动态申请内存空间后,如果我们发现过去申请的空间太小/大了,想要修改空间大小,就可以使用realloc()函数。

参数:realloc()函数有两个参数,分别为void*类型和size_t类型。

  • memblock参数表示要调整的内存空间的地址,void*表示此处可以放任意类型的指针,根据内存空间中存放数据的数据类型填写该指针类型。
  • size表示调整之后新的内存空间的大小。

返回值:调整之后的内存的起始地址。

注意:

realloc()函数的调整存在两种情况:

  • 想要调整为比原来更大的空间时:
  1. 原空间后有足够大的空间:直接在原空间后进行扩容即可。
  2. 原空间后没有足够大的空间:在内存空间中重新找一个能满足要求的连续空间块来使用,并且系统会自动把原来数据拷贝到这块新的空间中。此时返回的指针值并非原来的内存空间地址,而是一个新的内存空间地址,因此注意realloc()函数的使用,最好不要直接用原内存块指针接受realloc()函数返回值结果,如果realloc()失败,返回NULL,会导致原空间不能再使用但也没被回收而导致内存泄漏

tips:

如果realloc()函数中memblock参数是空指针,则相当于malloc()函数。


3.free()

动态内存管理函数及应用--通讯录管理系统(1)_内存空间_03

功能:Deallocates or frees a memory block.

          专门用于动态内存的释放和回收。 

参数:要释放内存空间的地址。

返回值:无返回值。


4.calloc()

动态内存管理函数及应用--通讯录管理系统(1)_通讯录管理_04

功能:Allocates an array in memory with elements initialized to 0.

          在内存中开辟有num个元素的数组,每个元素大小为size字节,并把每个字节初始化为0。

参数:开辟num个大小为size字节的内存空间。

返回值:返回类型是void*,指向所申请的内存空间的地址,可以使用强制类型转换修改指针类型。


动态内存函数应用--通讯录管理系统


应用描述:

使用动态内存管理实现通讯录管理系统

应具备的功能有:

  • 动态申请空间存储联系人信息(姓名、电话、地址)
  • 添加联系人
  • 删除联系人
  • 查询联系人
  • 修改联系人信息
  • 显示系统中全部的联系人信息
  • 销毁通信录系统


  1. 联系人信息结构体定义
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写出更好的博客。希望本篇文章对您有帮助,我们下期再见!

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

上一篇: Java内存区域 下一篇: Python - 字典1
  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
viMOS5Jem2go