动态内存管理 (上)

news2024/11/28 8:30:50

目录

1. 为什么要有动态内存分配

 2. malloc和free

2.1 malloc

2.1 1 malloc 申请空间和数组的空间有什么区别呢?

2.2 free

3. calloc和realloc

3.1 calloc

 3.2 realloc

 4. 常⻅的动态内存的错误

4.1 对NULL指针的解引⽤操作

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

 4.3对⾮动态开辟内存使⽤free释放

 4.4 使⽤free释放⼀块动态开辟内存的⼀部分

 4.5 对同⼀块动态内存多次释放

 4.6 动态开辟内存忘记释放(内存泄漏)

5. 题⽬1:

5.2 题⽬2:


1. 为什么要有动态内存分配

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

char arr[10] = {0};//在栈空间上开辟10个字节的连续空间

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

• 空间开辟⼤⼩是固定的。

• 数组在申明的时候,必须指定数组的⻓度,数组空间⼀旦确定了⼤⼩不能调整 但是对于空间的需求,不仅仅是上述的情况。

有时候我们需要的空间⼤⼩在程序运⾏的时候才能知 道,那数组的编译时开辟空间的⽅式就不能满⾜了。 C语⾔引⼊了动态内存开辟,让程序员⾃⼰可以申请和释放空间,就⽐较灵活了。

 2. malloc和free

2.1 malloc

void* malloc (size_t size);

 这个函数向内存申请⼀块连续可⽤的空间,并返回指向这块空间的指针。

• 如果开辟成功,则返回⼀个指向开辟好空间的指针

。 • 如果开辟失败,则返回⼀个 NULL 指针,因此malloc的返回值⼀定要做检查。

• 返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使⽤的时候使⽤者⾃ ⼰来决定。

• 如果参数 size 为0,malloc的⾏为是标准是未定义的,取决于编译器。malloc的头文件是<stdlib.h>

那么malloc如何开辟和使用呢?


#include <stdio.h>
#include <stdlib.h>
int main()
{
	int* p = (int*)malloc(10 * sizeof(int));//malloc 默认的,类型是 void 所以得强转
	if (p == NULL)
	{
		//空间开辟失败
		perror(malloc);
		return 1;//return返回1 是异常的
	}
	//成功就可以使用
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = i + 1;

	}


	return 0;
}

 当我们把十个数字都进去 ,会是怎样的呢?

 

2.1 1 malloc 申请空间和数组的空间有什么区别呢?

1.动态内存大小可以调节,

2.开辟的空间不一样,还记得前面给大家说的 局部变量,全局变量的存放吗?

忘了的话也没关系,我在给大家复习一下。

 大家应该有所理解了吧。

当然上面的代码还是不是很完善,malloc需要加上free 把内存空间释放。

2.2 free

C语⾔提供了另外⼀个函数free,专⻔是⽤来做动态内存的释放和回收的,函数原型如下:

void free (void* ptr);

 free函数⽤来释放动态开辟的内存。

• 如果参数 ptr 指向的空间不是动态开辟的,那free函数的⾏为是未定义的。

• 如果参数 ptr 是NULL指针,则函数什么事都不做。

malloc和free都声明在 stdlib.h 头⽂件中

我们看看free 在内存中如何实现的。

#include <stdio.h>
#include <stdlib.h>
int main()
{
	int* p = (int*)malloc(10 * sizeof(int));//malloc 默认的,类型是 void 所以得强转
	if (p == NULL)
	{
		//空间开辟失败
		perror("malloc");
		return 1;//return返回1 是异常的
	}
	//成功就可以使用
	/*int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = i + 1;

	}*/
	free(p);
 	return 0;
}

 

 那么p指向的空间不属于当前程序,但是还可以找到这块空间, 这时候p就是野指针了。

那么有什么方法避免呢?

那就是在free后面 ,加 p =NULL; 就把这个栓起来

 可以发现加上了 p =NULL;真的就释放了

malloc 和free 最好成对使用。

3. calloc和realloc

3.1 calloc

void* calloc (size_t num, size_t size);

 函数的功能是为 num 个⼤⼩为 size 的元素开辟⼀块空间,并且把空间的每个字节初始化为0。

• 与函数 malloc 的区别只在于 calloc 会在返回地址之前把申请的空间的每个字节初始化为全 0。

 

#include <stdio.h>
#incldue <stdlib.h>
int main()
{
	int* p = (int*)calloc(10, 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;

 3.2 realloc

realloc函数的出现让动态内存管理更加灵活。

• 有时会我们发现过去申请的空间太⼩了,有时候我们⼜会觉得申请的空间过⼤了,那为了合理的使 ⽤内存,我们⼀定会对内存的⼤⼩做灵活的调整。

那 realloc 函数就可以做到对动态开辟内存⼤ ⼩的调整。

void* realloc (void* ptr, size_t size);

 ptr 是要调整的内存地址

• size 调整之后新⼤⼩

• 返回值为调整之后的内存起始位置。

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

• realloc在调整内存空间的是存在两种情况:

◦ 情况1:原有空间之后有⾜够⼤的空间 ◦

情况2:原有空间之后没有⾜够⼤的空间

 情况1

当是情况1 的时候,要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发⽣变化。

情况2

当是情况2 的时候,原有空间之后没有⾜够多的空间时,扩展的⽅法是:在堆空间上另找⼀个合适⼤⼩ 的连续空间来使⽤,将旧地址数据拷贝到新地址数据,旧地址释放。这样函数返回的是⼀个新的内存地址

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


		//想要空间变成20字节,
		int* ptr = (int*)realloc(p,20 * sizeof(int));
		if (ptr != NULL)
		{
			p = ptr;
		}



		free(p);  
	p = NULL;

	return 0;
}

 4. 常⻅的动态内存的错误

4.1 对NULL指针的解引⽤操作

void test()

{ int *p = (int *)malloc(INT_MAX/4);

*p = 20;//如果p的值是NULL,就会有问题

free(p);

}

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

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

    test();
 

 就会出现越界访问

 4.3对⾮动态开辟内存使⽤free释放

int main()
{
    int a = 10;
    int* p = &a;
    free(p);
    p = NULL;

    return 0;
}

 4.4 使⽤free释放⼀块动态开辟内存的⼀部分

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

}

 4.5 对同⼀块动态内存多次释放

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

 4.6 动态开辟内存忘记释放(内存泄漏)

void test()
{
	int flag = 1;

	int* p = (int*)malloc(10 * sizeof(int));
	if (p == NULL)
	{
		return;
	}
	if (flag == 1)//如果执行了这里,无法执行后面,那么可能会导致内存的泄露。
	{
		return;
	}

	free(p);
	p = NULL;
 }
int main()
{

	test();

}

int main()
{
    int* p = (int*) realloc(NULL,40);//== malloc (40*sizeof(int ))
    if (p == NULL)
    {

    }
    return 0;
}

5. 题⽬1:

可以来看看哪里出了问题。

void GetMemory(char* p)
{
	p = (char*)malloc(100);
}
void Test(void)
{
	char* str = NULL;
	GetMemory(str);
	strcpy(str, "hello world");
	printf(str);
}

void GetMemory(char* p)// 形参是实参的一块临时拷贝
{
	p = (char*)malloc(100);
}
void Test(void)
{
	char* str = NULL;//因为传的是空指针,
	GetMemory(str);//把str的值传过去,
	strcpy(str, "hello world");
	printf(str);// 最后的结果是程序是崩溃,还存着内存泄露的问题,因为malloc 无法释放。
}

那么如何修改呢? 

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void GetMemory(char** p)//一级指针传参,二级指针接受
{	
	*p = (char*)malloc(100);
}
void Test(void)
{
	char* str = NULL;
	GetMemory(&str);//把地址传过去
	strcpy(str, "hello world");
	printf(str);
	free(str);//释放空间
	str = NULL;
}
int main()
{
	Test();


	return 0;
}

5.2 题⽬2:

char* GetMemory(void)
{
	char p[] = "hello world";
	return p;
}
void Test(void)
{
	char* str = NULL;
	str = GetMemory();
	printf(str);
}
int main()
{
	Test();

	return 0;
}

这个题目到底能不能运行呢?

他会打印随机值 ,这是为什么呢,因为在形参使用完后就销毁了,所以传的就是随机值,

 今天先到这吧 下回再分说

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

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

相关文章

CSS面试真题 part2

CSS面试真题 part2 11、css3新增了哪些新特性&#xff1f;12、css3动画有哪些&#xff1f;13、介绍一下grid网格布局14、说说flexbox&#xff08;弹性盒布局模型&#xff09;&#xff0c;以及使用场景&#xff1f;15、说说设备像素、css像素、设备独立像素、dpr、ppi之间的区别…

分机绑定线路和线路组(mod_cti基于FreeSWITCH)

文章目录 前言相关问题&#xff1a; 联系我们解决方案1. 创建线路2. 创建线路组3. 分机绑定线路组 前言 顶顶通呼叫中心中间件如果想要能外呼到手机上的话&#xff0c;那就必须对接能外呼的线路&#xff0c;这才可以实现分机与手机的通话。 相关问题&#xff1a; 如何设置一…

开发工具(上)

前面我们在Linux部分了解文件权限&#xff0c;和基本指令的内容&#xff0c;但对于开发工具还是没有很多的接触&#xff0c;现在这一篇就是主要讲基础的工具&#xff1b;如yum&#xff0c;yum源&#xff0c;包管理器等等&#xff1b; Linux中的安装软件&#xff1a; 源码安装 …

第23章 - Elasticsearch 洞悉你的查询:如何在上线前发现潜在问题!

文章目录 1. 前言2. Profile API - 查询优化2.1 Profile API 简单介绍2.2 查询结果图形化2.3 Profile 注意事项 3. Explain API - 解释查询 1. 前言 在第 21 章中&#xff0c;我介绍了 Elasticsearch 的读优化&#xff0c;但你是否曾疑惑&#xff1a;如何在上线前判断查询的耗…

Java项目-基于Springboot的农机电招平台项目(源码+说明).zip

作者&#xff1a;计算机学长阿伟 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、ElementUI等&#xff0c;“文末源码”。 开发运行环境 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBoot、Vue、Mybaits Plus、ELementUI工具&#xff1a;IDEA/…

基于因果推理的强对流降水临近预报问题研究

我国地域辽阔&#xff0c;自然条件复杂&#xff0c;灾害性天气种类繁多&#xff0c;地区差异性大。雷雨大风、冰雹、短时强降水等强对流天气是造成经济损失、危害生命安全最严重的一类灾害性天气。由于强对流降水具有高强度、小空间尺度等特点&#xff0c;一直是气象预报领域的…

前端js html css 基础巩固6

这样可以当做一个字典 来使用 每次 点击 键盘上的字母或数字 就可以获得 keyCode 这个 在实际应用中还是有可能使到的 所以大家可以练习一下 直接上代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta…

精选的四款强大视频压缩工具的整理:

大家好&#xff01;今天我来跟大家分享一下我使用过的几款视频压缩软件的体验感受&#xff0c;以及它们各自的好用之处&#xff1b;在这个信息爆炸的时代&#xff0c;视频文件越来越大&#xff0c;如何快速有效地压缩视频&#xff0c;同时还能保持较好的画质&#xff0c;是很多…

html+css+js实现Badge 标记

实现效果&#xff1a; 代码实现&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Badge…

【黑马Redis原理篇】Redis网络模型

来源视频 [16,27] 文章目录 1.用户空间和内核空间空间划分缓冲区 2.IO模型2.1 阻塞IO2.2 非阻塞IO2.3 IO多路复用2.3.1 阻塞和非阻塞的对比2.3.2 IO多路复用2.3.3 监听FD方式、通知的方式&#xff0c;有多种实现 2.4 信号驱动IO2.5 异步IO2.6 真正的同步和异步 1.用户空间和内…

opencv环境配置-适配b站阿童木的opencv教程

首先&#xff0c;opencv作为一个库文件&#xff0c;目的是为了让更多人不需要学习底层像素操作就能上手视觉技术&#xff0c;所以他适配很多环境&#xff0c;目前电脑端我知道的就可以适配C语言 C Python MCU端就是openmv跟他最类似&#xff0c;还有个k210 canmv 阿童木教的…

考研前所学的c语言01(2024/10/15)

1.变量由字母数字下划线组成&#xff0c;但是首字母只能是字母和下划线 2.基本函数01 3.基本代码02&#xff08;符号常量&#xff09; 4. A 是字符常量&#xff08;character constant&#xff09;。它表示单个字符&#xff0c;并且它的类型是 char&#xff0c;一个字节 "…

mysql connect -- C api编译链接问题,接口介绍(初始化和销毁,连接,执行sql语句,获取结果集的元数据和数据,设置编码格式)

目录 mysql connect 介绍 开发环境 编译链接问题 编译 链接 接口介绍 初始化和销毁 mysql_init() 句柄 mysql_close() 链接数据库 mysql_real_connect() 参数 返回值 show processlist 给mysql下达命令 mysql_query() 参数 返回值 查询结果的获取 引入 …

HarmonyOS NEXT 应用开发实战(七、知乎日报轮播图的完整实现)

在今天的博文中&#xff0c;我们将深入探讨如何在 HarmonyOS NEXT 中使用 ArkUI 实现一个轮播图组件。我们将通过一个示例代码来演示这个完整的过程&#xff0c;其中包含获取数据、管理数据源以及渲染组件等多个部分。 先来看下最终实现效果&#xff1a; 项目准备 首先&#…

JMeter之mqtt-jmeter 插件介绍

前言 mqtt-jmeter插件是JMeter中的一个第三方插件&#xff0c;用于支持MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;协议的性能测试。MQTT是一种轻量级的发布/订阅消息传输协议&#xff0c;广泛应用于物联网和传感器网络中。 一、安装插件 mqtt-jmeter项目…

【智能算法应用】雪消融优化算法求解二维路径规划问题

摘要 本文研究了雪消融优化算法在二维路径规划问题中的应用。该算法基于自然界中雪消融现象的模拟&#xff0c;通过优化策略寻找无人机路径的最优解。实验结果表明&#xff0c;该算法在路径规划中表现出较高的效率和收敛速度&#xff0c;能够有效地避开障碍物并找到代价最低的…

基于SpringBoot+Vue的校园周边美食探索及分享平台的设计与实现(带文档)

基于SpringBootVue的校园周边美食探索及分享平台的设计与实现&#xff08;带文档) 开发语言:Java数据库:MySQL技术:SpringBootMyBatisVue等工具:IDEA/Ecilpse、Navicat、Maven 源码 校园周边美食探索及分享平台是一个旨在为校园用户提供便捷的美食发现和分享服务的系统。该平…

我的JAVA项目构建

1.Maven maven就是pip 设置maven下载的的jar包位置 换源 下载插件maven-search 配置dependency 2.Tomcat 设置环境变量JAVA_HOME 设置编码方式 方框就是路径的前缀 3.Servlet 新建项目 写一个类继承HttpServlet&#xff0c;复写doGet(应对Get请求)&#xff0c;doPost(应对…

vue组件传值之$attrs

1.概述&#xff1a;$attrs用于实现当前组件的父组件&#xff0c;向当前组件的子组件通信&#xff08;祖-》孙&#xff09; 2.具体说明&#xff1a;$attrs是一个对象&#xff0c;包含所有父组件传入的标签属性。 注意&#xff1a;$attrs会自动排除props中声明的属性&#xff0…

从0开始深度学习(14)——模型选择、欠拟合、过拟合

① 模型在训练数据上拟合的比在潜在分布中更接近的现象&#xff0c;就叫过拟合&#xff08;overfitting&#xff09; ② 用于对抗过拟合的技术称为正则化&#xff08;regularization&#xff09; 1 训练误差和泛化误差 ①训练误差&#xff08;training error&#xff09;&…