解密动态内存管理的奥秘(含内存4个函数)

news2024/11/26 20:51:12


目录

一.为什么存在动态内存管理

二.动态内存函数的介绍

1. malloc函数(memory  alloc  内存开辟)

函数介绍:

malloc函数使用举例代码:

2.free(释放) 

函数介绍:

代码的示例:

3.calloc

函数介绍:

代码示例:

运行结果:

4.realloc

函数介绍:

使用示例代码:

常见的动态内存管理的错误

1.对NULL指针进行解引用操作

2.对动态开辟的空间越界访问

3.对非动态开辟的空间使用free

4.使用free释放一块动态开辟的内存中的一部分

5.对同一块内存多次释放

6.动态内存开辟忘记释放,造成内存泄漏


一.为什么存在动态内存管理

我们常见的内存开辟方式:

int  a =  20;               //在栈空间上开辟四个字节

int  arr[10] = { 0 };     //在栈空间上开辟40个字节

但是上的开辟空间方式有两个特点:

1.开辟的空间的大小是固定的;

2.数组在申明的时候,必须指定固定的长度,它所需的内存在编译时分配,有可能用不完造成浪费,也有可能后期不够用;

但是下在我们实际所需求中,不仅仅是上面的两种情况,有时候我们需要的空间大小在程序运行时才知道,那么上述方式开辟空间就不能够满足,所以有了动态内存开辟。

二.动态内存函数的介绍

必备知识:

内存大概的划分:

栈区: 主要存放局部变量,形式参数等等

堆区: 动态内存的开辟,malloc,free,calloc,realloc等等

静态区: 全局变量,静态变量等等

1. malloc函数(memory  alloc  内存开辟)

函数介绍:

void*   malloc(size_t    size)

malloc函数可以向内存申请一块连续的空间,并返回指向这块空间的指针;

值得注意的是:

1. 如果开辟成功,将返回一个指向开辟好了的空间的指针;

如果开辟失败,将返回空指针NULL;

所以在开辟后需要判断是否开辟成功,检查返回值;

2. 函数返回的是空指针,malloc函数并不知道开辟空间的类型,所以在使用的时候需要自己决定(使用强制类型转换);

3.如果size为0时,malloc函数的行为是未定义的,取决于编译器;

4.malloc函数开辟的空间里面存放的是随机值(下面代码可验证);

5.malloc函数申请的空间,当程序退出时,还给操作系统,当程序不退出时,动态开辟的空间不会主动还给操作系统,需要用free函数来释放;

malloc函数使用举例代码:

int main()
{
	int* p = (int *)malloc(40);   //这里需要的是int*类型的指针,所以用()强制类型转换为int*
	if (p == NULL)
	{
		perror(malloc);           //判断是否开辟成功
		return 1;
	}
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d\n",*(p+i));
	}

	free(p);
    p=NULL;         //将p置为空指针,不要让p成为野指针

	return 0;
}

运行结果:

-842150451
-842150451
-842150451
-842150451
-842150451
-842150451
-842150451
-842150451
-842150451
-842150451

2.free(释放) 

函数介绍:

void*   free (void*  p)

C语言提供的free函数是专门用来做动态内存的释放和回收的

free是用来释放动态开辟的内存

1.如果void* p所指向的内存不是动态开辟的,free函数的行为是未定义的;

2.如果void* p所指向的是NULL(空指针),则free函数什么都不做;

代码的示例:

int main()
{
	int* p = (int *)malloc(40);   //这里需要的是int*类型的指针,所以用()强制类型转换为int*
	if (p == NULL)
	{
		perror(malloc);           //判断是否开辟成功
		return 1;
	}
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d\n",*(p+i));
	}

	free(p);       //使用完该空间后释放
    p=NULL;         //将p置为空指针,不要让p成为野指针

	return 0;
}

3.calloc

函数介绍:

void*   calloc (size_t  num , size_t   size)

功能:是为num个大小为size的元素开辟一块空间,并吃初始化为0;

与malloc函数类似,只是会将开辟的空间内容初始化为0;

代码示例:

int main()
{
    int* p = (int* )calloc(40,sizeof(int));
	if (p == NULL)
	{
		perror(calloc);
		return 1;
	}
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ",*(p+i));
	}
	free(p);
	p = NULL;

	return 0;
}

运行结果:

0   0   0   0   0   0   0   0   0   0

4.realloc

realloc函数可以让内存管理更加灵活;

函数介绍:

viod*   realloc    (void*   ptr,size_t   size)

realloc函数可以调整我们申请的空间的大小;

其中ptr是要调整的内存地址;

size是调整之后的大小;

返回值是为调整之后的内存起始位置;

当void*  ptr  为一个空指针时,功能和malloc一样;

值得注意的是:这个函数调整之后,可能将原来内存中的数据移动到新的空间;

分为两种情况;

1.原有空间的后面有足够大的空间时(即原有空间后面的剩余空间有所需增加空间那么大),就直接在原有空间后面开辟,并且返回指向原来空间的指针;

2.当原有的空间后面没有足够大的空间来增加空间,则需要重新找一个空间开辟,并且将原有空间的内容复制过去,然后释放旧的空间的内存,返回新的地址;

使用示例代码:

int main()
{
	int* p =(int* )malloc(40);
	if (p == NULL)
	{
		perror("malloc");
		return 1;
	}
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		p[i] = i+1;
	}
	int* ret = realloc(p,80);
	{
		if (ret == NULL)
		{
			perror("realloc");
			return 1;
		}
		else
		{
			p = ret;
		}
	}

	for (i = 0; i < 20; i++)
	{
		printf("%d ",*(p+i));
	}

	free(p);
	p = NULL;


	return 0;
}

运行结果:

1  2  3  4  5  6  7  8  9  10  -842150451  -842150451  -842150451  -842150451  -842150451  -842150451  -842150451  -842150451 -842150451 -842150451

常见的动态内存管理的错误

1.对NULL指针进行解引用操作

      void   test

     {   

              int  *p  =  (int *)malloc(INT_MAX);

              *p = 20;    //如果p是空指针就有问题;

               free(p);

     }

当用内存函数开辟好空间后,不检查是否开辟成功就直接使用;

2.对动态开辟的空间越界访问

int* p = (int*)malloc(40);

int i = 0;

for(i=0;i<12;i++)                  //  i=10,11,就越界访问了

{

     printf("%d ",*(p+i));

}

3.对非动态开辟的空间使用free

int a = 10;

int* p = &a;

free(p);            //  错误的

4.使用free释放一块动态开辟的内存中的一部分

int* p=(int *)malloc(40);

p++;

free(p);           //p++后,已经不是指向的原开辟的内存,而是指向的一部分;

5.对同一块内存多次释放

int* p = (int*)malloc(40);

free(p);

free(p);

6.动态内存开辟忘记释放,造成内存泄漏

void   test()

{

         int * p =(int*)mmalloc(40)

          if(NULL!=p)

          {

                 *p=20;

          }

                                                     //使用完后忘记释放,出函数p销毁,但是40个字节的空间还在

int  main()

{

         test();

          while(1);                               //死循环,程序不结束,40个字节永远用不到

}

                                                             作者:GOXXT

                                                             专注分享在学习道路上的知识笔记



本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/778341.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux 网络通信epoll详解( 10 ) -【Linux通信架构系列 】

系列文章目录 C技能系列 Linux通信架构系列 C高性能优化编程系列 深入理解软件架构设计系列 高级C并发线程编程 期待你的关注哦&#xff01;&#xff01;&#xff01; 现在的一切都是为将来的梦想编织翅膀&#xff0c;让梦想在现实中展翅高飞。 Now everything is for the…

《网络是怎样连接的》(二.1)

(83条消息) 《网络是怎样连接的》&#xff08;一&#xff09;_qq_38480311的博客-CSDN博客 本文主要取材于 《网络是怎样连接的》 第二章。 目录 &#xff08;1&#xff09;创建套接字 &#xff08;2&#xff09;连接服务器 &#xff08;3&#xff09;收发数据 &#xf…

文本预处理——文本处理的基本方法

目录 什么是分词jieba分词特性精确模式分词全模式分词搜索引擎模式分词使用用户自定义词典 命名实体识别词性标注 什么是分词 jieba分词特性 精确模式分词 import jieba content工信处女干事每月经过下属科室都要亲口交代24口交换机等技术性器件的安装工作 print(jieba.lcut(co…

《零基础入门学习Python》第055讲:论一只爬虫的自我修养3:隐藏

0. 请写下这一节课你学习到的内容&#xff1a;格式不限&#xff0c;回忆并复述是加强记忆的好方式&#xff01; 上节课我们说过了&#xff0c;有一些网站比较痛恨爬虫程序&#xff0c;它们不喜欢被程序所访问&#xff0c;所以它们会检查链接的来源&#xff0c;如果说来源不是正…

ONGUI

public class ONGUI : MonoBehaviour {private void OnGUI() {GUI.Label(new Rect(0,0,100,250),"ONGUI");} }说明是以左上角为原点来算的

Spring Cloud【服务网关Gateway(三大核心概念、入门案例、路由规则 、Java API构建路由、动态路由、断言功能详解)】(六)

目录 服务网关Gateway_三大核心概念 服务网关Gateway_入门案例 服务网关Gateway_路由规则 服务网关Gateway_Java API构建路由 服务网关Gateway_动态路由 服务网关Gateway_断言功能详解 服务网关Gateway_三大核心概念 路由(Route) 这是网关的基本构建块。它由一个ID&am…

小程序自定义导航栏

效果图 代码 app.json文件下 "window":{"navigationStyle": "custom" //增加此属性},app.js文件 //计算高度 App({onLaunch() {wx.getSystemInfo({ // 获取设备信息success: (res) > {this.globalData.systeminfo res//导航栏let statusB…

springboot整合quartz通过数据库配置任务调度简单办法

简介 Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目&#xff0c;它可以与J2EE与J2SE应用程序相结合也可以单独使用。在java企业级应用中&#xff0c;Quartz是使用最广泛的定时调度框架。 在Quartz中的主要概念&#xff1a; Scheduler&#xff1a;调度任务…

C语言中文件的读写

不争输赢&#xff0c;只问对错 文章目录 一、文件的概述 二、什么是读写文件 三、文件处理的函数 1.文件的打开与关闭 2.文件的顺序读写 文件的顺序读写相关函数 scanf 和 printf 家族的对比及其区分 3.文件的随机读写 文件的随机读写函数 四、文件缓冲区 五…

【el-tree查询并高亮】vue使用el-tree组件,搜索展开并选中对应节点,高亮搜索的关键字,过滤后高亮关键字,两种方法

第一种&#xff08;直接展开并高亮关键字&#xff09; 效果图这样的&#xff0c;会把所有的有这些关键字的节点都展开 代码&#xff1a; 这里的逻辑就是通过递归循环把所有和关键字匹配的节点筛选出来 然后通过setCheckedKeys方法把他展开选中 然后通过filterReal把关键字高亮…

Hadoop——DataGrip连接MySQL|Hive

1、下载 DataGrip下载&#xff1a;DataGrip: The Cross-Platform IDE for Databases & SQL by JetBrains 2、破解 破解链接&#xff1a;https://www.cnblogs.com/xiaohuhu/p/17218430.html 3、启动环境 启动Hadoop&#xff1a;到Hadoop的sbin目录下右键管理员身份运行…

数学建模学习(2):数学建模各类常用的算法全解析

一、评价类算法 常见的评价算法 1.层次分析法 基本思想 是定性与定量相结合的多准则决策、评价方法。将决策的有关元素分解成 目标层、准则层和方案层 &#xff0c;并通过人们的 判断对决策方案的 优劣进行排序 &#xff0c;在此基础上进行定性和定量分析。它把人的思维过程…

预处理详解

目录 一、预定义符号 二、#define 1.认识#define 2.使用#define 2.1#define定义常量 2.2#define定义宏 2.3#define的替换规则 三、宏定义的其他内容 1.#和## 1.1# 1.2## 2.宏的副作用 3.宏的命名规则 4.undef 5.条件编译 一、预定义符号 #include<stdio.h> int…

通过FPGA实现基于RS232串口的指令发送并控制显示器中目标位置

目录 1.算法理论概述 串口通信模块 指令解析模块 位置控制模块 显示器驱动模块 2.部分核心程序 3.算法运行软件版本 4.算法运行效果图预览 5.算法完整程序工程 1.算法理论概述 通过FPGA实现基于RS232串口的指令发送并控制显示器中目标位置是一种常见的应用场景&#x…

双向不循环链表的认识和基础操作(节点创建,头插头删,尾插尾删,输出和逆置)

头定义&#xff1a; typedef char datatype[20];//datatypechar[20] typedef struct Node {//数据域 数据元素datatype data;//指针域 下一个节点地址struct Node* next;//指针域 上一个节点地址struct Node* prev; }*DoubleLink; 创建节点&#xff1a; DoubleLink create_n…

校园电气安全风险分析及预防措施 安科瑞 许敏

摘要:校园属于人员密集场所&#xff0c;若安全风险排查、管控不到位&#xff0c;可能导致安全事故发生&#xff0c;造成严重事故后果。校园电气设备设施引起的电气火灾和触电等事故&#xff0c;是构成校园安全威胁之一&#xff0c;笔者通过对校园发生的电气安全事故案例原因分析…

一次线上OOM问题的个人复盘

我们一个java服务上线后&#xff0c;偶尔会发生内存OOM(Out Of Memory)问题&#xff0c;但由于OOM导致服务不响应请求&#xff0c;健康检查多次不通过&#xff0c;最后部署平台kill了java进程&#xff0c;这导致定位这次OOM问题也变得困难起来。 最终&#xff0c;在多次review代…

react目录结构

比较全面的react目录结构。 目录详解 assets&#xff1a;放置原始资源文件。 components&#xff1a;存放全局组件。 contants&#xff1a;常量文件夹&#xff0c;存放常量。 i18n&#xff1a;i18n国际化&#xff0c;各种语言的翻译。 pages&#xff1a;页面文件夹。 r…

es添加索引命令行和浏览器添加索引--图文详解

一、添加索引 创建索引 curl -X PUT "localhost:9200/my-index-00001?pretty" 获取索引 curl -X GET "localhost:9200/my-index-000001?pretty" 获取全部的索引 curl -X GET "http://localhost:9200/_cat/indices?v" 获取索引映射 cur…

2023 Pycharm 给项目配置解释器 基于已经创建的conda虚拟环境

我在2019年开始使用Pycharm作为python的IDE&#xff0c;最近配置解释器时&#xff0c;法线网上的方法大概过时了&#xff0c;自己尝试了好多次才发现新版本的Pycharm的解释配置方法&#xff0c;故记于此 背景描述&#xff1a; 我是用conda管理环境的&#xff0c;我已经创建好一…