首页 > 系统相关 >动态内存管理函数及应用--通讯录管理系统(1)

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

时间:2023-10-14 21:07:39浏览次数:45  
标签:con1 -- 联系人 pnode 通讯录 动态内存 printf con

引言:


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


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)_malloc_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)_malloc_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写出更好的博客。希望本篇文章对您有帮助,我们下期再见!

标签:con1,--,联系人,pnode,通讯录,动态内存,printf,con
From: https://blog.51cto.com/u_16191221/7862872

相关文章

  • 我遇到过自己做开发版然后卖 然后没人买,亏了的
    自主研发并销售产品,但未能获得预期的销售额,甚至导致亏损,确实会让人感到沮丧。这种情况下,可以考虑以下几点建议:分析市场需求:在研发和销售产品之前,需要对市场进行充分的调研,了解目标客户群体的需求和购买力。同时,需要关注竞争对手的产品,了解他们的定价策略、产品特点和市场份额等信息......
  • #yyds干货盘点# LeetCode程序员面试金典:整数转换英文表示
    题目:将非负整数 num 转换为其对应的英文表示。 示例1:输入:num=123输出:"OneHundredTwentyThree"示例2:输入:num=12345输出:"TwelveThousandThreeHundredFortyFive"示例3:输入:num=1234567输出:"OneMillionTwoHundredThirtyFourThousandFiveHundredSixtySe......
  • #yyds干货盘点# LeetCode程序员面试金典:最小操作次数使数组元素相等
    1.简述:给你一个长度为 n 的整数数组,每次操作将会使 n-1 个元素增加 1 。返回让数组所有元素相等的最小操作次数。 示例1:输入:nums=[1,2,3]输出:3解释:只需要3次操作(注意每次操作会增加两个元素的值):[1,2,3]=>[2,3,3]=>[3,4,3]=>[4,4,4]示例2:输入:nums=[1......
  • mysql报错:You must reset your password using ALTER USER statement before executin
    新安装mysql后,登录后,执行任何命令都会报错:YoumustresetyourpasswordusingALTERUSERstatementbeforeexecutingthisstatement.【解决办法】MySQL版本5.7.6版本以前用户可以使用如下命令:mysql>SETPASSWORD=PASSWORD('Admin2022!');MySQL版本5.7.6版本开始的用户可以使......
  • 关于Hyperledger Fabric区块链中的测试网络
    HyperledgerFabric区块链运行时核心架构当然,上图中仅给出了只有一个组织的示例。Fabric网络中测试网络的重要作用有哪些?在Fabric网络中,测试网络的重要作用主要包括以下几点:学习和了解Fabric:通过测试网络,可以帮助初学者和开发者更深入地了解Fabric的基础架构、运行机制以及相关技术......
  • 【精品】使用druid 获取数据库表的信息
    Maven依赖<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifac......
  • Linux(CentOS)之Nginx安装及配置
    一,复制nginx下载链接http://nginx.org/en/download.html二,下载nginx1.注意切换到root用户2.注意在/usr/local/目录下3.使用命令(PS:-c的参数即为上一步你复制的地址)wget-chttp://nginx.org/download/nginx-1.24.0.tar.gz三,解压tar-zxvfnginx-1.40.0.tar.gz四,安装依赖yumi......
  • 无涯教程-Matplotlib - 3D线框图(Wireframe)
    线框图采用值的网格并将其投影到指定的三维表面上,并使生成的三维形式非常容易可视化。plot_wireframe()函数用于此目的-frommpl_toolkitsimportmplot3dimportnumpyasnpimportmatplotlib.pyplotaspltdeff(x,y):returnnp.sin(np.sqrt(x**2+y**2)) x=......
  • arraylist扩容原理
    ArrayList是Java中的动态数组,其扩容原理是在元素数量超过当前数组容量时,创建一个更大容量的新数组,并将所有元素从旧数组复制到新数组。下面是ArrayList扩容的基本原理:初始容量:当你创建一个ArrayList对象时,它会有一个初始容量,通常为10。这个容量可以根据需要进行调整。元素添加:当你......
  • python20
    题目:一个数如果恰好等于它的因子之和,这个数就称为"完数"。例如6=1+2+3.编程找出1000以内的所有完数。程序分析:请参照程序Python练习实例14。程序源代码:实例#!/usr/bin/python#-*-coding:UTF-8-*-fromsysimportstdoutforjinrange(2,1001):k=[]n=-1s=jfor......