当前位置: 首页 > news >正文

第二十一章 (动态内存管理)

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

2. malloc和free

3. calloc和realloc

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

5. 动态内存经典笔试题分析

6. 总结C/C++中程序内存区域划分

1.为什么要有动态内存管理
我们目前已经掌握的内存开辟方式有

int main()
{int num = 0;  //开辟4个字节int arr[10] = { 1,2,3,4,5,6 };return 0;
}

但是上边的开辟空间的方式有两个特点
1.空间开辟大小是固定的。
2. 数组在申明的时候,必须指定数组的长度,
数组空间一旦确定大小就不能调整

解决方法:
在这里插入图片描述
二、malloc和free
2.1 malloc
c语言提供了一个动态内存开辟的函数:
在这里插入图片描述
这个函数向内存申请的是一块连续可用的空间,并返回指向这块空间的指针

1.开辟成功,则返回一个指向开辟好空间的指针

2.开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查

3.返回类型的是void * ,所以malloc函数并不知道开辟空间的类型,具体在使用者使用的时候自己来选择

4.如果参数size为0,malloc函数的行为标准是为定义的,取决于编译器。

2.2 free
c 语言还提供了另一个函数free,是专门用来做动态内存的释放和回收的(一般是要与malloc函数同时使用的),函数原型如下
在这里插入图片描述
1.如果参数ptr指向的空间不是动态开辟的,那么free函数是为定义的
2.如果参数ptr函数是NULL的话,则函数不需要做任何事

malloc 和free都在stdlib.h头文件中

#include<stdio.h>
#include<string.h>
#include<stdlib.h>int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int ret = sizeof(arr) / sizeof(arr[0]);int* ptr = NULL;ptr=(int *)malloc(ret * sizeof(int));  //开辟内存if (ptr != NULL){for (int i = 0; i < ret; i++){*(ptr + i) = i;printf("%d ", *(ptr + i));}}free(ptr);  //释放内存ptr = NULL;  //这一步是否有必要?//(这里的作用是防止如果再次使用ptr进行判断,可以避免进行的访问)return 0;
}

这里我们来画图解释一下
在这里插入图片描述
三、calloc和recallo
除了malloc函数以外c语言还提供了另外一个函数calloc函数,calloc函数也可以用来进行动态内存的分配。原型如下:
在这里插入图片描述
1.函数的功能是为num个大小为size的元素开辟一块空间,并且把每个字节初始化为。
2.与malloc函数的区别只在与calloc会在返回地址之前把申请的空间的每个字节初始化为全0.

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

在这里插入图片描述
这里我们可以知道如果我们想对申请的空间进行初始化的时候,就可以使用calloc函数来解决。

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

  • 在有些情况下我们会发现申请的空间会过大或者过小,这时候我们就可以用realloc函数来对我们开辟内存的大小进行调整。
    在这里插入图片描述
    这里我们来解释一下
    1.ptr是要调整的内存地址
    2.size是调整之后新大小
    注意这个函数是在原有的内存大小的基础上,将原来的数据移动到的空间中
    3.realloc在调整内存空间是存在两种情况的
    3.1 原有的空间有足够大的空间情况
    3.2 原有空间之后没有足够大的空间
    在这里插入图片描述

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

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

由于这两种情况我们再使用realloc函数的时候就需要多注意一下

int main()
{int* ptr = (int*)malloc(25 * sizeof(int)); //这里是100个字节if (ptr != NULL){for (int i = 0; i < 50; i++){*ptr = i;printf("%d ", *ptr);}}//那么如果我们想要更大的内存呢?//int* ptr = realloc(ptr, 1000);//这种写法是有问题的,如果我们开辟了一块新的内存之后,还这样用那么可能就会导致访问的失败int* p = realloc(ptr, 1000);//用这种方式是最好的if (p != NULL) //判断如果p是不为空的话{ptr = p; // 把新地址赋给ptr,我们就可以使用ptr来操作新地址}free(ptr);ptr = NULL;return 0;}

四、常见的动态内存的错
这里我们来举几个例子
1.

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);}
void test()
{int a = 10;int* pr = &a;*pr = 10;free(pr);  //对非动态内存地址进行释放pr = NULL;  
}int main()
{test();return 0;
}
void test()
{int* p = (int*)malloc(10 * sizeof(int));p++;free(p);  //释放的位置不是起始位置return 0;
}int main()
{test();return 0;
}
void test(){int* p = (int*)malloc(10 * sizeof(int));free(p);free(p);  //多次释放return 0;}int main(){test();return 0;}
void test()
{int i = 0;int* p = (int*)malloc(10 * sizeof(int));if (NULL == p){exit(EXIT_FAILURE);}for (i = 0; i <= 9; i++){*(p + i) = i;//当i是10的时候越界访问printf("%d ", *(p + i));}//没有释放内存,可能会导致内存泄露
}int main(){test();return 0;}

void GetMemory(char* p)
{p = (char*)malloc(100);//没有返回值
}
void Test(void)
{char* str = NULL;GetMemory(str);//这里的函数值没有接收,所以并没有什么用strcpy(str, "hello world");  //所以这里的str为0printf(str);
}int main()
{text();return 0;
}

该代码会报错

void Test(void)
{char* str = (char*)malloc(100); //这里没有判断是否为0strcpy(str, "hello");free(str);  //释放空间后没有置为0,可能就会导致内存泄露if (str != NULL){strcpy(str, "world");printf(str);}
}int main()
{Test();return 0;
}

六、总结c/c++中程序内存区域划分

1、栈区:在执行函数的时候,函数内的局部变量的储存单元都可以在栈上创建,函数执行结束的时候这些储存单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率高,但是分配的内存容量有限。栈区主要分配的是局部变量、函数参数、返回数据、返回地址等。

2.堆区:一般由程序员分配释放,如果程序员不释放,程序结束的时候可能由os来释放。分配方式类似于链表

3.数据段(静态区):(static)存放全局变量、静态数据。程序结束后由系统释放。
4. 代码段:存放函数体(类成员函数和全局变量)的二进制代码。

相关文章:

第二十一章 (动态内存管理)

1. 为什么要有动态内存分配 2. malloc和free 3. calloc和realloc 4. 常⻅的动态内存的错误 5. 动态内存经典笔试题分析 6. 总结C/C中程序内存区域划分 1.为什么要有动态内存管理 我们目前已经掌握的内存开辟方式有 int main() {int num 0; //开辟4个字节int arr[10] …...

机器学习框架总结

机器学习框架是用于构建、训练、评估和部署机器学习模型的工具和库的集合。它们简化了模型开发过程&#xff0c;并提供了预构建的功能、优化的计算性能和对深度学习、监督学习、无监督学习等技术的支持。下面是一些主要的机器学习框架的详细介绍&#xff1a; 1. TensorFlow 1…...

docker pull 超时的问题如何解决

docker不能使用&#xff0c;使用之前的阿里云镜像失败。。。 搜了各种解决方法&#xff0c;感谢B站UP主 <iframe src"//player.bilibili.com/player.html?isOutsidetrue&aid113173361331402&bvidBV1KstBeEEQR&cid25942297878&p1" scrolling"…...

【数学分析笔记】第4章第3节 导数四则运算和反函数求导法则(2)

4. 微分 4.3 导数四则运算与反函数求导法则 双曲正弦函数 sh ⁡ x e x − e − x 2 \sh x\frac{e^x-e^{-x}}{2} shx2ex−e−x​ 双曲余弦函数 ch ⁡ x e x e − x 2 \ch x\frac{e^xe^{-x}}{2} chx2exe−x​ ch ⁡ 2 x − sh ⁡ 2 x 1 \ch^2 x-\sh^2 x1 ch2x−sh2x1 ( e…...

【2024】基于mysqldump的数据备份与恢复

基于mysqldump备份与恢复 mysqldump是一个用于备份 MySQL 数据库的实用工具。 它可以将数据库的结构&#xff08;如数据库、表、视图、存储过程等的定义&#xff09;和数据&#xff08;表中的记录&#xff09;导出为文本文件&#xff0c;这些文本文件可以包含 SQL 语句&#…...

家用无线路由器配置

一.首先进行线路连接。如下图&#xff1a;"光猫LAN口"—网线—"路由器WAN口"。 注意&#xff1a;家用光纤宽带一般选择使用200兆宽带到1000兆&#xff0c;如果网速不达标请查看路由器是否是千兆路由器。千兆路由器通常是双频的&#xff0c;支持两个信号一个…...

模拟算法(4)_外观数列

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 模拟算法(4)_外观数列 收录于专栏【经典算法练习】 本专栏旨在分享学习算法的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 1. 题目链…...

vsomeip用到的socket

概述&#xff1a; ​ vsomeip用到的socket的代码全部都在implementation\endpoints目录下面&#xff0c;主要分布在下面六个endpoint类中&#xff1a; local_client_endpoint_impl // 本地客户端socket&#xff08;UDS Socket或者127.0.0.1的socket&#xff09;local_server…...

MFC有三个选项:MFC ActiveX控件、MFC应用程序、MFC DLL,如何选择?

深耕AI&#xff1a;互联网行业 算法研发工程师 ​ 目录 MFC ActiveX 控件 控件的类型 标准控件 自定义控件 ActiveX控件 MFC ActiveX控件 标准/自定义控件 MFC ActiveX控件分类 3种MFC如何选择&#xff1f; MFC ActiveX控件 MFC 应用程序 MFC DLL 总结 举例说明…...

边缘概率 | 条件概率

关于什么是边缘概率分布和条件概率分布&#xff0c;在理论上&#xff0c;我自己也还没有理解&#xff0c;那么现在就根据我学习到的理解方式来记录一下&#xff0c;有错误指出&#xff0c;请大家指正&#xff01;&#xff01;&#xff01; 例如&#xff0c;一个箱子里有十个乒乓…...

深入浅出:现代JavaScript开发者必知必会的Web性能优化技巧

亲爱的读者们&#xff0c;欢迎来到本期博客。今天&#xff0c;我们将深入探讨JavaScript开发者在日常工作中如何提升Web性能。在快节奏的Web开发世界中&#xff0c;性能优化至关重要。本文将分享一些实用技巧&#xff0c;帮助你构建快速、高效的Web应用。 1. 使用CDN加速资源加…...

【S32K3 RTD LLD篇5】K344 ADC SW+HW trigger

【S32K3 RTD LLD篇5】K344 ADC SWHW trigger 一&#xff0c;文档简介二&#xff0c;ADC SW HW 触发2.1 软硬件平台2.2 SWADC 软件触发2.3 SWBCTUADC 软件BCTU触发2.4 PITTRIGMUXADC 硬件PIT TRIGUMX触发2.5 EMIOSBCTUHWADC硬件EMIOS BCTU触发2.6 EMIOSBCTUHW LISTADC硬件EMIOS …...

TransFormer 视频笔记

TransFormer BasicsAttention单头注意力 single head attentionQ&#xff1a; query 查寻矩阵 128*12288K key matrix 128*12288SoftMax 归一 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/19e3cf1ea28442eca60d5fc1303921f4.png)Value matrix 12288*12288 MLP Bas…...

前端的混合全栈之路Meteor篇(三):发布订阅示例代码及如何将Meteor的响应数据映射到vue3的reactive系统

Meteor 3.0 是一个功能强大的全栈 JavaScript 框架&#xff0c;特别适合实时应用程序的开发。它的核心机制之一就包括发布-订阅&#xff08;Publish-Subscribe&#xff09;模型&#xff0c;它允许服务器端发布数据&#xff0c;客户端订阅并实时更新。本文将介绍如何在 Meteor 3…...

自动驾驶系列—颠覆未来驾驶:深入解析自动驾驶线控转向系统技术

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…...

Webstorm 中对 Node.js 后端项目进行断点调试

首先&#xff0c;肯定需要有一个启动服务器的命令脚本。 然后&#xff0c;写一个 debug 的配置&#xff1a; 然后&#xff0c;debug 模式 启动项目和 启动调试服务&#xff1a; 最后&#xff0c;发送请求&#xff0c;即可调试&#xff1a; 这几个关键按钮含义&#xff1a; 重启…...

VUE前后端分离毕业设计题目项目有哪些,VUE程序开发常见毕业论文设计推荐

目录 0 为什么选择Vue.js 1 Vue.js 的主要特点 2 前后端分离毕业设计项目推荐 3 后端推荐 4 总结 0 为什么选择Vue.js 使用Vue.js开发计算机毕业设计是一个很好的选择&#xff0c;因为它不仅具有现代前端框架的所有优点&#xff0c;还能让你专注于构建高性能、高可用性的W…...

一、Spring Boot集成Spring Security之自动装配

Spring Boot集成Spring Security之自动装配介绍 一、实现功能及软件版本说明二、创建Spring Boot项目三、查看自动装配配置类四、自动装配配置类之SecurityAutoConfiguration1、SecurityAutoConfiguration部分源码2、主要作用3、SpringBootWebSecurityConfiguration3.1、Spring…...

计数相关的题 Python 力扣

2284. 最多单词数的发件人 给你一个聊天记录&#xff0c;共包含 n 条信息。给你两个字符串数组 messages 和 senders &#xff0c;其中 messages[i] 是 senders[i] 发出的一条 信息 。 一条 信息 是若干用单个空格连接的 单词 &#xff0c;信息开头和结尾不会有多余空格。发件…...

Express内置的中间件(express.json和express.urlencoded)格式的请求体数据

目录 Express内置的中间件 express.json 中间件的使用 express.urlencoded 中间件的使用 express.urlencoded([options]) 解析req.body的兼容写法 Express内置的中间件 自 Express 4.16.0 版本开始&#xff0c;Express 内置了 3 个常用的中间件&#xff0c;极大的提高了 …...

变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析

一、变量声明设计&#xff1a;let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性&#xff0c;这种设计体现了语言的核心哲学。以下是深度解析&#xff1a; 1.1 设计理念剖析 安全优先原则&#xff1a;默认不可变强制开发者明确声明意图 let x 5; …...

手游刚开服就被攻击怎么办?如何防御DDoS?

开服初期是手游最脆弱的阶段&#xff0c;极易成为DDoS攻击的目标。一旦遭遇攻击&#xff0c;可能导致服务器瘫痪、玩家流失&#xff0c;甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案&#xff0c;帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...

dedecms 织梦自定义表单留言增加ajax验证码功能

增加ajax功能模块&#xff0c;用户不点击提交按钮&#xff0c;只要输入框失去焦点&#xff0c;就会提前提示验证码是否正确。 一&#xff0c;模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...

土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等

&#x1f50d; 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术&#xff0c;可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势&#xff0c;还能有效评价重大生态工程…...

uniapp中使用aixos 报错

问题&#xff1a; 在uniapp中使用aixos&#xff0c;运行后报如下错误&#xff1a; AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...

如何更改默认 Crontab 编辑器 ?

在 Linux 领域中&#xff0c;crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用&#xff0c;用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益&#xff0c;允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...

C++ 设计模式 《小明的奶茶加料风波》

&#x1f468;‍&#x1f393; 模式名称&#xff1a;装饰器模式&#xff08;Decorator Pattern&#xff09; &#x1f466; 小明最近上线了校园奶茶配送功能&#xff0c;业务火爆&#xff0c;大家都在加料&#xff1a; 有的同学要加波霸 &#x1f7e4;&#xff0c;有的要加椰果…...

LCTF液晶可调谐滤波器在多光谱相机捕捉无人机目标检测中的作用

中达瑞和自2005年成立以来&#xff0c;一直在光谱成像领域深度钻研和发展&#xff0c;始终致力于研发高性能、高可靠性的光谱成像相机&#xff0c;为科研院校提供更优的产品和服务。在《低空背景下无人机目标的光谱特征研究及目标检测应用》这篇论文中提到中达瑞和 LCTF 作为多…...

篇章二 论坛系统——系统设计

目录 2.系统设计 2.1 技术选型 2.2 设计数据库结构 2.2.1 数据库实体 1. 数据库设计 1.1 数据库名: forum db 1.2 表的设计 1.3 编写SQL 2.系统设计 2.1 技术选型 2.2 设计数据库结构 2.2.1 数据库实体 通过需求分析获得概念类并结合业务实现过程中的技术需要&#x…...

WebRTC调研

WebRTC是什么&#xff0c;为什么&#xff0c;如何使用 WebRTC有什么优势 WebRTC Architecture Amazon KVS WebRTC 其它厂商WebRTC 海康门禁WebRTC 海康门禁其他界面整理 威视通WebRTC 局域网 Google浏览器 Microsoft Edge 公网 RTSP RTMP NVR ONVIF SIP SRT WebRTC协…...