12. 内存管理

一、内存的组织方式

  程序员编写完程序之后,程序要先加载在计算机的内存中,再运行程序。在 C++ 中,不同数据在内存中所存储的位置也不一样。全局变量存储在内存中的静态存储区,非静态的局部变量存储在内存中的动态存储区(栈)。临时使用的数据建立动态内存分配区域,需要的时候开辟,不需要时及时释放(堆)。

  通过内存注释方式可以看出,堆用来存放动态分配内存空间,而栈用来存放局部数据变量、函数的参数以及调用函数与被调函数的联系。

  在内存的全局存储空间中,用于程序动态分配和释放的内存块称为自由存储空间,通常也称之为堆。在 C 程序 中,使用 malloc() 函数和 free() 函数来从堆中动态的分配内存和释放内存。在 C++ 中仍然可以这么做,但 C++ 推荐使用 new 和 delete 关键字动态管理内存。

  程序不会像处理堆那样在栈中显示地分配内存。当程序调用函数或声明局部变量时,系统将自动分配内存。

  栈是一个后进先出的压入弹出式的数据结构。在程序运行时,需要每次向栈中压入一个对象,然后栈指针向下移动一个位置。当系统从栈中弹出一个对象时,最晚进栈的对象将被弹出,然后栈指针向上移动一个位置。如果栈指针位于栈顶,则表示栈是空的;如果栈指针指向最下面的数据项的后一个位置,则表示栈为满的。

二、动态内存管理

  new 关键字根据类型来确定需要多少个字节的内存。然后,它找到这样的内存,并返回其地址。为一个数据对象(可以是结构,也可以是基本数据类型)获取并指定分配内存的通用格式如下:

类型名 * 指针变量名 = new 类型名;

  需要在两个地方指定数据类型:用来指定需要什么样的内存和用来声明合适的指针。

  new 分配的内存块通常与常规变量声明分配的内存块不同,常规变量的值都存储在栈(stack)的内存区域中,而 new 从堆中分配内存。

  当需要内存时,可以使用 new 申请内存,使用完内存后,需要使用 delete 释放内存,将其归还给内存池。使用 delete 时,后面要加上指向内存块的指针。

  我们还可以为一个指针重新指向另一个新分配的内存块。我们一定要配对的使用 new 和 delete,否则会发生内存泄露问题,也就是说,被分配的内存再也无法使用了。如果内存泄露严重,则程序将由于不断寻找更多的内存导致内存耗尽而终止。还有不要充实释放已经释放的内存块。C++ 标准指出,这样做的后果是不确定的。

#include <iostream>using namespace std;int main(void)
{int a = 10;int *p1 = new int;*p1 = a;int *p2 = new int(a*10);cout << "*p1: " << *p1 << endl;cout << "*p2: " << *p2 << endl;delete p1;delete p2;return 0;
}

只能使用 delete 释放使用 new 分配的内存。然后,对于空指针使用 delete 是安全的。

三、使用new创建动态数组

  在编译时给数组分配内存被称为 静态联编,意味着数组是在编译时加入到程序的。但使用 new 时,如果在运行阶段需要数组,则创建它,如果不需要,则不创建。还可以在程序运行时选择数组的长度。这称为 动态联编,意味着数组是在程序运行时创建的。这种数组叫作动态数组。使用静态联编时,必须在编写程序时指定数组的长度。使用动态联编时,程序将在运行时确定数组的长度。

  在 C++ 中,创建动态数组只需要将数组的元素类型和元素数目告诉 new 即可。必须在类型名后加上方括号,其中包含元素的数目。new 运算符将返回第一个元素的地址。

类型名 数组名 = new 类型名[数组大小];

  当程序使用完 new 分配的数组后,应该使用 delete 释放内存。

delete [] 数组名;

  其中,方括号告诉程序,应释放整个数组,而不仅仅是指针指向的元素。如果使用 new 时,不带方括号,则使用 delete 时,也应该不带方括号。如果使用 new 时带方括号,则使用 delete 时也应带方括号。

#include <iostream>using namespace std;int main(void)
{int length = 0;cout << "请输入要创建的整型数组的元素个数: " << endl;cin >> length;int * array = new int[length];cout << "请填充整型数组元素,中间用空格分隔" << endl;for (int i = 0; i < length; i++){cin >> array[i];}cout << "填充后的数组为:" << endl;for (int i = 0; i < length; i++){cout << array[i] << " ";}cout << endl;delete[] array;return 0;
}

四、使用new创建动态结构

  通过使用 new,可以创建动态结构。同样,动态意味着内存是在运行时,而不是编译时分配的。创建动态结构时,不能将成员运算符句点用于结构名,因为这种结构没有名称,只知道它的地址。C++ 为这种情况提供了一个运算符:箭头运算符(->)。该运算符由连字符和大于号组成,可用于指向结构指针。

#include <iostream>using namespace std;struct Person
{string name;int age;
};int main(void)
{Person * person = new Person;cout << "请输入姓名:" << endl;cin >> person->name;cout << "请输入年龄:" << endl;cin >> person->age;cout << "{name: " << person->name << ", age: " << person->age << "}";delete person;return 0;
}

五、动态分配内存的基本原则

  1. 避免分配大量的小内存块。分配堆上的内存有一些系统开销,所以分配许多小的内存块比分配几个大的内存块的系统开销大;
  2. 仅在需要时分配内存。只要使用完堆上的内存块,就需要及时释放它(如果使用动态分配内存,需要遵循谁分配,谁释放原则),否则可能出现内存泄露;
  3. 总是确保释放以分配过的内存。在编写分配内存的代码时,就需要确定在代码的什么地方释放内存;
  4. 在释放内存之前,确保不会无意中覆盖堆上已分配的内存地址,否则程序就会出现内存泄漏。在循环分配内存时,要特别小心。

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

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

相关文章

后台管理系统的通用权限解决方案(七)SpringBoot整合SpringEvent实现操作日志记录(基于注解和切面实现)

1 Spring Event框架 除了记录程序运行日志&#xff0c;在实际项目中一般还会记录操作日志&#xff0c;包括操作类型、操作时间、操作员、管理员IP、操作原因等等&#xff08;一般叫审计&#xff09;。 操作日志一般保存在数据库&#xff0c;方便管理员查询。通常的做法在每个…

视频设备一体化监控运维方案

随着平安城市、雪亮工程等项目建设的号召&#xff0c;视频监控系统的建设如火如荼地开展。无论在公共场所、企业单位、住宅小区、矿山工地还是交通枢纽&#xff0c;视频监控系统已成为保障安全、维护秩序和提升管理效率的重要工具。但由于对视频监控系统中的前端设备&#xff0…

二十八、Python基础语法(面向对象-下)

一、self 从函数的语法上来看, self 是形参 , 是一个普通的参数,那么在调用的时候,就需要传递实参值。从调用上看, 我们没有给 self 这个形参传递实参值, 但是 Python 解释器会自动的将调用这个方法的对象&#xff0c;作为实参值传递给 self。 class Dog:def eat(self):print…

【Leecode】Leecode刷题之路第37天之解数独

题目出处 37-解数独-题目出处 题目描述 个人解法 思路&#xff1a; todo代码示例&#xff1a;&#xff08;Java&#xff09; todo复杂度分析 todo官方解法 37-解数独-官方解法 方法1&#xff1a;回溯 思路&#xff1a; 代码示例&#xff1a;&#xff08;Java&#xff09; p…

【golang/navmesh】使用recast navigation进行寻路

目录 说在前面安装使用可视化 说在前面 go version&#xff1a;1.20.2 linux/amd64操作系统&#xff1a;wsl2detour-go版本&#xff1a;v0.2.0github&#xff1a;这里&#xff0c;求star! 安装 使用go mod安装即可go get github.com/o0olele/detour-go使用 使用场景模型构建n…

qt QFormLayout详解

QFormLayout 是 Qt 框架中用于创建表单布局的一个类&#xff0c;适合于将标签和输入控件整齐地排列在一起。它可以帮助开发者轻松构建用户输入界面&#xff0c;尤其是在处理表单时。 QFormLayout以两列的形式展示其子项&#xff0c;常用于创建“标签-字段”对的布局。其中&…

电脑小白必看|电脑安装常用软件简单小技巧

前言 最近同事换了新电脑&#xff0c;问我怎么下载常用软件&#xff1f; 我反问了一下&#xff1a;什么常用软件呢&#xff1f; 她说&#xff1a;微信、QQ、钉钉、酷狗、wps这种类型的软件。 哦豁&#xff0c;那其实很简单&#xff0c;但很多人还是没学会。小白之前分享过一…

RocketMQ 消息消费失败的处理机制

在分布式消息系统中&#xff0c;处理消费失败的消息是非常关键的一环。 RocketMQ 提供了一套完整的消息消费失败处理机制&#xff0c;下面我将简要介绍一下其处理逻辑。 截图代码版本&#xff1a;4.9.8 步骤1 当消息消费失败时&#xff0c;RocketMQ会发送一个code为36的请求到…

数据结构算法学习方法经验总结

DSA:Data Structures, Algorithms, and Problem-Solving Techniques 三大核心支柱 一次学习一个主题&#xff0c;按照如下顺序学习 如何开始学习新的主题 学习资源 https://www.youtube.com/playlist?listPLDN4rrl48XKpZkf03iYFl-O29szjTrs_O (Algorithms) https://ww…

Linux 操作系统的诞生与发展历程

目录 背景与起源 诞生过程 特点与影响 背景与起源 历史背景&#xff1a; 1980年代末至1990年代初&#xff0c;计算机操作系统市场主要由商业软件主导&#xff0c;如DOS、Windows以及Unix的各种版本。然而&#xff0c;这些系统往往价格昂贵&#xff0c;且源代码不开放&#…

第三届北京国际水利科技博览会将于25年3月在国家会议中心召开

由中国农业节水和农村供水技术协会、北京水利学会、振威国际会展集团等单位联合主办的第三届北京国际水利科技博览会暨供水技术与设备展&#xff08;北京水利展&#xff09;将于2025年3月31日至4月2日在北京•国家会议中心举办&#xff01; 博览会以“新制造、新服务、新业态”…

贪心算法习题其二【力扣】【算法学习day.19】

前言 ###我做这类文档一个重要的目的还是给正在学习的大家提供方向&#xff08;例如想要掌握基础用法&#xff0c;该刷哪些题&#xff1f;&#xff09;我的解析也不会做的非常详细&#xff0c;只会提供思路和一些关键点&#xff0c;力扣上的大佬们的题解质量是非常非常高滴&am…

Linux中NFS配置

文章目录 一、NFS介绍1.1、NFS的工作流程1.2、NFS主要涉及的软件包1.3、NFS的主要配置文件 二、安装NFS2.1、更新yum2.2、安装NFS服务2.3、配置NFS服务器2.4、启动NFS服务2.5、配置防火墙&#xff08;如果启用了防火墙&#xff0c;需要允许NFS相关的端口通过&#xff09;2.6、生…

Docker | 将本地项目发布到阿里云的实现流程

发布到阿里云 本地镜像发布到阿里云流程具体流程1. docker commit 生成新镜像文件2. 查看镜像3. 阿里云开发者平台选择控制台&#xff0c;进入容器镜像服务&#xff0c;选择个人实例创建命名空间仓库名称进入管理界面获得脚本推送到阿里云 补充&#xff1a; docker tag 命令基本…

Qt指定程序编译生成文件的位置

shadow build: [基础]Qt Creator 的 Shadow build(影子构建)-CSDN博客 影子构建&#xff1a;将源码路径和构建路径分开&#xff08;生成的makefile文件和其他产物都不放到源码路径&#xff09;&#xff0c;以此来保证源码路径的清洁。 实验1&#xff1a; 我创建了两个项目:…

嵌入式常用功能之通讯协议1--串口

嵌入式常用功能之通讯协议1--串口&#xff08;本文&#xff09; 嵌入式常用功能之通讯协议1--IIC 嵌入式常用功能之通讯协议1--SPI&#xff08;待定&#xff09; ...... 一、串口协议简介 1&#xff0c;简介 UART(异步串行通信)&#xff1a;时钟基准不是同一个&#xff08…

「Mac畅玩鸿蒙与硬件10」鸿蒙开发环境配置篇10 - 项目实战:计数器应用

本篇将通过一个简单的计数器应用,带你体验鸿蒙开发环境的实际操作流程。本项目主要练习组件的使用、事件响应和状态管理,帮助开发者熟悉基本的应用构建流程。 关键词 计数器应用组件操作事件响应状态管理HarmonyOS 应用开发一、创建计数器项目 1.1 在 DevEco Studio 中新建项…

Python | Leetcode Python题解之第513题找树左下角的值

题目&#xff1a; 题解&#xff1a; class Solution:def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:q deque([root])while q:node q.popleft()if node.right:q.append(node.right)if node.left:q.append(node.left)ans node.valreturn ans

操作系统实验记录

实验零:虚拟机安装 一、安装vmware虚拟机 与vmware匹配搜索结果 - 考拉软件 (rjctx.com),下载17.5.1版本即可下载后对照教程安装 二、下载iso虚拟驱动 搜索清华大学镜像网站,点击再搜ubuntu,下载这个4.1GB的iso文件安装后打开vmware虚拟机 三、配置vmware虚拟机 右键管…

适配器模式:类适配器与对象适配器

适配器模式是一种结构性设计模式&#xff0c;旨在将一个接口转换成客户端所期望的另一种接口。它通常用于解决由于接口不兼容而导致的类之间的通信问题。适配器模式主要有两种实现方式&#xff1a;类适配器和对象适配器。下面&#xff0c;我们将详细探讨这两种方式的优缺点及适…