动态内存管理详解

news2024/9/28 17:32:43

动态内存管理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(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()
{
	//代码1
	int num = 0;
	scanf("%d", &num);
	int arr[num] = { 0 };
	return 0;
}

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

再看一个例子:

int main()
{
	//代码2
	int* 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.coloradmin.cn/o/906725.html

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

相关文章

素材准备——准备用于标注和训练的图片素材——从视频监控视频中生成图片素材

为了实现我们对特定场景下的图像识别功能,我们需要依托YOLO V8工具,对大量的图片进行目标标准和训练。因此我们首先要做的一项工作便是准备大量的用于标准和训练做续的图片。 由于在实际项目中,特别是以公安交管所需要的场景中,我们很难单纯依托网络下载的方式获得所需要的…

通达信接口开发需要执行哪些源码?

通常进行开发通达信接口&#xff0c;则需要执行以下开发文档&#xff1a; 1.1 名称 功能 基本函数 Init API 初始化 Deinit API 反初始化 Logon 登录交易账户 Logoff 登出交易账户 QueryData 查询各类交易数据 QueryHistoryData 查询各类历史数据 …

数字孪生农业|数字乡村建设解决方案

2019年5月&#xff0c;中共中央办公厅、国务院办公厅发布《数字乡村发展战略纲要》&#xff0c;2022年1月&#xff0c;中央网信办、农业农村部等10部门印发《数字乡村发展行动计划&#xff08;2022-2025年&#xff09;》&#xff0c;一系列政策文件为数字乡村的建设指明了方向和…

想要让你的设计更具吸引力?试试SOLIDWORKS Visualize!

Visualize用于轻松创建图像动画和交互式内容生成照片质量的图像强大工具集拥有以下突出优势 优势一CPUGPU混合渲染 Visualize可采用GPU进行渲染&#xff0c;解决了CPU占用100%的问题&#xff0c;使得在渲染图片的同时也能轻松完成其他工作任务。 优势二AI降噪器 Visualize 降…

Camtasia导入srt字幕乱码

我们在使用camtasia制作视频项目时&#xff0c;有时为了用户体验需要导入srt格式的字幕文件&#xff0c;在操作无误的情况下&#xff0c;一顿操作猛如虎之后字幕顺利的导入到软件中了&#xff0c;但字幕却出现了乱码的现象。如下图所示&#xff1a; 如何解决srt乱码问题呢&…

jsp 协同过滤 图书管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 协同过滤 图书管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境 为TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为My…

恒运资本:算力概念强势拉升,亚康股份“20cm”涨停,首都在线等大涨

算力概念21日盘中强势拉升&#xff0c;到发稿&#xff0c;亚康股份“20cm”涨停&#xff0c;首都在线、汇金股份涨逾11%&#xff0c;鸿博股份亦涨停&#xff0c;南凌科技涨近9%&#xff0c;科创信息、神州数码、铜牛信息等涨超7%。 音讯面上&#xff0c;8月19日&#xff0c;202…

认识Redis

1. 前置操作 以下内容基于CentOS 1.1. 安装 yum -y install redis 1.2. 启动 redis-server /etc/redis.conf & 1.3. 打开 redis-cli 1.4. 停止 redis-cli shutdown 1.5. 设置远程连接 修改 /etc/redis/redis.conf 修改 bind 127.0.0.1为 bind 0.0.0.0 1.6. 使用…

【李沐3】3.5、图像分类数据集

# %matplotlib inline # 上述代码是一个注释&#xff0c;用于在Jupyter Notebook等环境中显示Matplotlib绘图的结果在单元格内部显示&#xff0c;而不是弹出新的窗口。import torch import torchvision from torch.utils import data from torchvision import transforms from …

A - Bone Collector(01背包)

Many years ago , in Teddy’s hometown there was a man who was called “Bone Collector”. This man like to collect varies of bones , such as dog’s , cow’s , also he went to the grave … The bone collector had a big bag with a volume of V ,and along his tr…

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

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

Pytorch建立MyDataLoader过程详解

简介 torch.utils.data.DataLoader(dataset, batch_size1, shuffleNone, samplerNone, batch_samplerNone, num_workers0, collate_fnNone, pin_memoryFalse, drop_lastFalse, timeout0, worker_init_fnNone, multiprocessing_contextNone, generatorNone, *, prefetch_factorN…

attention is all you need 超参数 私自解读

这几个超参数可变&#xff0c;但是也不能变得太多&#xff1b; 语言本身是复杂的&#xff0c;但可以按照多套语法体系来解剖语言现象&#xff0c;所以超参数是有一定可变的范围&#xff1b; 为什么是6层编码器和解码器呢&#xff1f; 人类的语言可以按照六个层次来组织&#…

Day14-2-NodeJS后端开发流程

Day14-NodeJS后端工程化流程 一 apifox工具 apifox是目前最好的接口调试工具 1 环境搭建 安装登录创建项目接口里面创建对应文件夹在指定的文件夹里面创建接口2 GET请求 1 apifox发送GET请求 2 后端接收GET请求 router.get("/getUserinfo"

拼多多商品详情API接入站点,实时数据json格式示例

作为国内最大的电商平台之一&#xff0c;拼多多数据采集具有多个维度。 有人需要采集商品信息&#xff0c;包括品类、品牌、产品名、价格、销量等字段&#xff0c;以了解商品销售状况、热门商品属性&#xff0c;进行市场扩大和重要决策&#xff1b; 商品数据&#xff1a;拼…

Navicat 蝉联 2023年度 DBTA 读者选择奖的“最佳数据库管理员解决方案”奖项和 DBTA 100 强名单

近日&#xff0c;Database Trends and Applications (简称 DBTA) 颁发的“读者选择奖”获奖名单新鲜出炉&#xff0c;Navicat 蝉联 2023 年度 DBTA 读者选择奖的“最佳数据库管理员&#xff08;DBA&#xff09;解决方案”奖项和 DBTA 100 强名单&#xff0c;我们感到无比荣幸和…

自动化编排工具Terraform介绍(一)

Terraform是什么&#xff1f;: Terraform 是 HashiCorp 公司旗下的 Provision Infrastructure 产品, 是 AWS APN Technology Partner 与 AWS DevOps Competency Partner。Terraform 是一个 IT 基础架构自动化编排工具&#xff0c;它的口号是“Write, Plan, and Create …

springMVC 已解密的登录请求

问题描述&#xff1a; 解决方案&#xff1a; 1.对用户所输入的密码在页面进行MD5加密并反馈至密码输入框。 2. 手动生成SSL安全访问证书&#xff1b;在此不做介绍&#xff0c;相关方法可通过网上查找&#xff1b; 3. 将产品HTTP访问方式改为SSL安全访问方式&#xff1b;在Ap…

Fast DDS(1)

1、什么是数据分发服务(DDS)&#xff1a; 数据分发服务 (DDS) 是一种以数据为中心的通信协议&#xff0c;用于分布式软件应用程序通信。它描述了支持数据提供者和数据消费者之间通信的通信应用程序编程接口&#xff08;API&#xff09;和通信语义。 由于它是一个以数据为中心的…

java云智慧工地管理平台系统源码

智慧工地将“互联网”的理念和技术引入建筑工地&#xff0c;从施工现场源头抓起&#xff0c;最大程度地收集人员、安全、环境、材料等关键业务数据&#xff0c;依托物联网、互联网&#xff0c;建立云端大数据管理平台&#xff0c;形成“端云大数据”的业务体系和新的管理模式&a…