动态内存管理详解

动态内存管理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-djdTekBo-1692581782529)(C:\Users\30539\AppData\Roaming\Typora\typora-user-images\image-20230811231624473.png)]

1.前言

目前来回顾一下想要在内存中开辟空间有哪些方法?

  • 创建变量: int a = 0;//在栈上开辟了4字节的空间
  • 创建数组: int arr[10] = { 0 };//在栈上开辟40字节的空间

但是这两种开辟方式都有两个特点:

  1. 开辟的内存空间大小是固定的。
  2. 数组在申明的时候,必须指定数组的长度,它所需要的内存在编译时分配。

但是对于空间的需求,不仅仅是上述的情况。有时候我们需要的空间大小在程序运行的时候才能知道, 那数组的编译时开辟空间的方式就不能满足了。此时就只能试试动态内存开辟了

2.动态内存函数的介绍

2.1 [malloc函数](malloc - C++ Reference (cplusplus.com))和free函数

用于开辟内存的函数:

void* malloc(size_t size);

这个函数能申请一块连续的指定大小为 size字节大小的内存,同时返回指向该内存的指针

  • 假若内存开辟成功,则返回一个指向开辟好的内存的指针。
  • 假如内存开辟失败,则返回NULL指针,所以在使用malloc函数的时候,一定要对函数的返回进行检查,不为NULL才能继续使用。
  • 要注意函数的返回值是一个空指针,可以指向任何类型空间,所以在接收返回值时,需要将其转换成我们需要的类型,再进行接收。
  • 假设给malloc函数的size参数传递的值为0,此时该函数的行为是未定义的,取决于编译器。

注意:malloc函数是在堆上开辟的空间,堆上的空间的释放只能通过两种方式:

  1. 等待程序运行结束自动释放。
  2. 使用free函数主动释放。

用于释放内存的函数:

void free(void* ptr);

free函数用于释放在堆上开辟的内存

  • 假如ptr所指向的空间不是动态开辟的,那么该行为是未定义的,极有可能报错。
  • 假若ptr的值为NULL,那么此时free函数什么都不做。

malloc和free函数的声明都在 stdlib.h头文件中。

接下来看几个例子:

int main()
{//代码1int num = 0;scanf("%d", &num);int arr[num] = { 0 };return 0;
}

这里的代码是会报错的,因为数组的创建方括号里的值必须是常量。要特别注意。

再看一个例子:

int main()
{//代码2int* ptr = NULL;ptr = (int*)malloc(num * sizeof(int));if (NULL != ptr)//判断ptr指针是否为空{int i = 0;for (i = 0; i < num; i++){*(ptr + i) = 0;}}free(ptr);//释放ptr所指向的动态内存ptr = NULL;//是否有必要?return 0;
}

这里在释放了动态开辟的空间之后,是否要将指向该内存的指针变量置为空呢?这里一定是要置为空的,可以有效防止后面对该指针进行解引用操作等。这是一种较好的习惯。

看看下一段代码:

int main()
{int* arr = (int*)malloc(sizeof(int) * 10);for (int i = 0; i<10; i++){printf("%d\n", arr[i]);}printf("\n");return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-31NdeQUD-1692581782530)(C:\Users\30539\AppData\Roaming\Typora\typora-user-images\image-20230812235016208.png)]

通过运行结果不难发现,malloc函数开辟的空间的值是随机值。经过malloc函数开辟的空间中的值都会是默认值。这里就可以使用接下来要介绍的calloc函数了。

2.2 calloc函数

用于动态开辟内存的函数:

void* calloc (size_t num, size_t size);
  • 函数的功能是:为num个大小为size的元素开辟空间,并且可以将开辟出的每个字节都初始化为0。
  • calloc函数与malloc函数的差别就是:malloc函数会在返回空间首地址之前将每个字节都初始化为0。

例子:

#include <stdio.h>
#include <stdlib.h>
int main()
{int *p = (int*)calloc(10, sizeof(int));if(NULL != p){//使用空间,这里忽略内容。}free(p);p = NULL;return 0;
}

如图所示,这里经过calloc函数开辟的空间的每一个字节都被设置成了0.所以我们对开辟的内存中的值有初始化的需求时,可以很方便的使用calloc函数来进行操作。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B0n0fUIW-1692581782531)(C:\Users\30539\AppData\Roaming\Typora\typora-user-images\image-20230813004848539.png)]

2.3realloc函数

void* realloc (void* ptr, size_t size);
  • realloc函数可以让动态内存管理更加灵活。

  • size变量的值是重新调整之后的内存空间的大小。

  • realloc函数的返回值是开辟的空间的起始地址。

  • 这个函数在调整原来空间的基础上,会将原来内存中的数据移动到新空间中。

  • realloc函数在对内存空间进行调整时,分为两种情况:

    1. 在原空间之后有足够的空间。
    2. 原有空间之后没有足够的空间。

    情况1:当是第一种情况时,就会直接在原来的内存空间之后追加空间,原本内存空间中的值不发生变化,函数的返回值仍然是原来内存空间的起始地址。

    情况2:由于realloca在内存中开辟的空间是连续的。所以就有可能存在在原来的空间之后没有足够的空间的情况。此时realloc函数就会在堆内存中寻找另一个合适的位置开辟空间,函数会返回新开辟的空间的起始地址,并且将原来内存中的数据拷贝进这零开辟的空间中,拷贝之后就会将原来的空间还给操作系统。

注意:当realloc开辟的空间较大时,就存在内存开辟失败的情况,此时realloc函数会返回一个空指针,所以在使用realloc函数时,一定要对其返回值是否为空进行检查。

3.常见的动态内存错误

1.对NULL指针的解引用操作

void test()
{int *p = (int *)malloc(INT_MAX/4);*p = 20;//如果p的值是NULL,就会有问题free(p);
}

这段代码中并没有对返回值进行检查,假若返回值为NULL那么就会有问题的。

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

void test()
{int i = 0;int *p = (int *)malloc(10*sizeof(int));if(NULL == p){exit(EXIT_FAILURE);}for(i=0; i<=10; i++){*(p+i) = i;//当i是10的时候越界访问}free(p);
}

这段代码中,当i的值为10时,就会出现越界访问的问题。

3.对非动态开辟的空间进行free释放操作

void test()
{int a = 10;int *p = &a;free(p);//ok?
}

注意:非动态开辟的空间是不能使用free函数进行释放的。

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

void test()
{int *p = (int *)malloc(100);p++;free(p);//p不再指向动态内存的起始位置
}

注意:不能使用free函数释放动态开辟的空间的一部分,编译器会报错的,也无法成功。

5.对同一块动态开辟的空间进行多次释放操作

void test()
{int *p = (int *)malloc(100);free(p);free(p);//重复释放
}

注意:当使用free函数对动态开辟的空间释放之后,要将该指针赋值为NULL,这样以后对该指针进行操作时,就会通过报错来提示我们。就比如这段代码,当第一次free之后,就对p指针赋值为空,那么下一次进行free操作时,就不会发生任何变化。

6.动态开辟的空间忘记释放(内存泄漏)

vvoid test()
{int *p = (int *)malloc(100);if(NULL != p){*p = 20;}
}
int main()
{test();while(1);
}

注意:当动态开辟的空间我们不会再对其进行使用时,一定及时释放该内存空间,否则会造成内存泄漏的问题。虽然程序结束会自动释放动态开辟的内存,但是对于那些长期运行的服务器来讲,它们中的程序几乎一直都在运行,不会停止。那么内存泄漏就是一个致命的问题了。

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

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

相关文章

安装搭建私有仓库 Harbor

目录 一. 准备环境 1.1安装 Docker 1.2安装 Docker Compose 二. 下载 Harbor 安装包 三. 解压安装包 四. 配置 Harbor 五. 安装 Harbor 六. 访问 Harbor 七. 创建项目、用户和角色 一. 准备环境 确保您的服务器满足 Harbor 的系统要求。最低要求是至少 2 核 CPU、4GB…

Azure应用程序网关

文章目录 什么是应用程序网关实战演练创建虚拟网络创建虚拟机创建应用程序网关测试搭建结果 什么是应用程序网关 Azure应用程序网关是一种托管服务&#xff0c;用于提供安全、可缩放的 Web 应用程序前端点的应用程序传送控制和保护。它可以通过 SSL 终止、cookie 基于会话持久…

【计算机网络八股】计算机网络(一)

目录 计算机网络的各层协议及作用&#xff1f;TCP和UDP的区别&#xff1f;UDP 和 TCP 对应的应用场景是什么&#xff1f;详细介绍一下 TCP 的三次握手机制&#xff1f;为什么需要三次握手&#xff0c;而不是两次&#xff1f;为什么要三次握手&#xff0c;而不是四次&#xff1f…

[C语言]分支语句和循环语句

[C语言]分支语句和循环语句 文章目录 [C语言]分支语句和循环语句C语言语句分类分支语句if语法结构else的匹配规则switch语句switch语句中的breakswitch语句中default 循环语句while循环while循环中的break和continuefor循环for循环中的break和continuefor循环的变种do while循环…

广告牌安全传感器,实时监测事故隐患尽在掌握

在现代城市中&#xff0c;广告牌作为商业宣传的重要媒介&#xff0c;已然成为城市中一道独特的风景线。然而&#xff0c;随着城市迅速发展&#xff0c;广告牌的安全问题也引起了大众关注。广告招牌一般悬挂于建筑物高处&#xff0c;量大面大。由于设计、材料、施工方法的缺陷&a…

函数栈帧的创建与销毁

目录 引言 基础知识 内存模型 ​ 寄存器的种类与功能 常用的汇编指令 函数栈帧创建与销毁 main()函数栈帧的创建 NO1. NO2. NO3. NO4. NO5. NO6. main()函数栈帧变量的创建 调用Add()函数栈帧的预备工作——传参 NO1. NO2. NO3. Add()函数栈帧的创建 …

C语言入门_Day 6布尔数与比较运算

目录 前言 1.布尔数 2.比较运算 3.易错点 4.思维导图 前言 除了算术计算以外&#xff0c;编程语言中还会大量使用比较运算&#xff0c;并会根据比较运算的结果是“真”还是“假”&#xff0c;来执行不同的代码。 当你想买一杯奶茶&#xff0c;准备支付的时候&#xff0c;支…

Codeforces EDU 151 Div.2

文章目录 A. Forbidden IntegerB. Come TogetherC. Strong PasswordD. Rating SystemE. Boxes and Balls A. Forbidden Integer Problem - A - Codeforces 给定整数n&#xff0c;从1~k中选择除了x的数&#xff0c;使这些数之和为n&#xff0c;每个数可以选择无限次 爆搜&…

[Vue]解决npm run dev报错node:internal/modules/cjs/loader:1031 throw err;

解决: 有2中方法&#xff0c;建议先尝试第一种&#xff0c;不行再第二种 第一种: 重新安装依赖环境 删除项目的node_modules文件夹&#xff0c;重新执行 # 安装依赖环境 npm install# 运行 npm run dev 我只用了第一种方法就可以了 &#xff0c;第二种方法从别的博主那看到…

【Java 动态数据统计图】动态数据统计思路案例(动态,排序,数组)二(113)

需求&#xff1a; 有一个List<Map<String.Object>>,存储了区域的数据&#xff0c; 数据是根据用户查询条件进行显示的&#xff1b;所以查询的数据是动态的&#xff1b;按区域维度统计每个区域出现的次数&#xff0c;并且按照次数的大小排序&#xff08;升序&#…

最新ChatGPT网站AI系统源码+详细图文搭建教程/支持GPT4.0/AI绘画/H5端/Prompt知识库/

一、前言 SparkAi系统是基于国外很火的ChatGPT进行开发的Ai智能问答系统。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。 那么如何搭建部署AI创作ChatGPT&#xff1f;小编这里写一个详细图文教程吧&#xff01…

从 Ansible Galaxy 使用角色

从 Ansible Galaxy 使用角色 根据下列要求&#xff0c;创建一个名为 /home/curtis/ansible/roles.yml 的 playbook &#xff1a; playbook 中包含一个 play&#xff0c; 该 play 在 balancers 主机组中的主机上运行并将使用 balancer 角色。 此角色配置一项服务&#xff0c;以…

Docker容器:docker镜像的创建及dockerfile

Docker容器&#xff1a;docker镜像的创建及dockerfile案例 一.docker镜像的三种创建方法 创建镜像有三种方法&#xff1a;基于现有镜像创建、基于本地模板创建及基于dockerfile创建 1.基于现有镜像创建 1.1 启动镜像 #首先启动一个镜像&#xff0c;在容器里做修改 docker …

SpringBoot常用注解-@PathVariable、@RequestParam 、@RequestBody

目录 PathVariable RequestParam RequestBody PathVariable PathVariable 获取url中的数据&#xff0c;绑定路径中的占位符参数到方法参数变量中&#xff0c;get或者post方式都可以&#xff0c;如果URL中无参数&#xff0c;将会出错 例如获取/login/id/name中的id值和name值 …

途乐证券|定增募资是什么意思?

作为融资手法之一&#xff0c;定增募资在企业中被广泛运用。但一般投资者对此或许不太了解&#xff0c;只知道它是一种融资手法。那么&#xff0c;定增募资到底是什么意思呢&#xff1f; 一、什么是定增募资&#xff1f; 定增募资即定向增发股票募集资金&#xff0c;是新股票发…

C++入门知识点——解决C语言不足

&#x1f636;‍&#x1f32b;️Take your time ! &#x1f636;‍&#x1f32b;️ &#x1f4a5;个人主页&#xff1a;&#x1f525;&#x1f525;&#x1f525;大魔王&#x1f525;&#x1f525;&#x1f525; &#x1f4a5;代码仓库&#xff1a;&#x1f525;&#x1f525;魔…

【C# 基础精讲】LINQ to Objects查询

LINQ to Objects是LINQ技术在C#中的一种应用&#xff0c;它专门用于对内存中的对象集合进行查询和操作。通过使用LINQ to Objects&#xff0c;您可以使用统一的语法来查询、过滤、排序、分组等操作各种.NET对象。本文将详细介绍LINQ to Objects的基本概念、常见的操作和示例&am…

Android Studio实现读取本地相册文件并展示

目录 原文链接效果 代码activity_main.xmlMainActivity 原文链接 效果 代码 activity_main.xml 需要有一个按钮和image来展示图片 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk…

Error creating bean with name ‘esUtils‘ defined in file

报错异常&#xff1a; 背景&#xff1a; esUtils在common服务中、启动media服务时候、报这个异常、后排查esUtils在启动时候发生异常引起的、在相关bean中加入try{}catch{}即可解决问题 String[] split url.split(","); HttpHost[] httpHosts new HttpHost[split.…

FirmAE 工具安装(解决克隆失败 网络问题解决)

FirmAE官方推荐使用Ubuntu 18.04系统进行安装部署&#xff0c;FirmAE工具的安装部署十分简单&#xff0c;只需要拉取工具仓库后执行安装脚本即可。 首先运行git clone --recursive https://kgithub.com/pr0v3rbs/FirmAE命令 拉取FirmAE工具仓库&#xff0c;因为网络的问题&…