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.mzph.cn/news/884252.shtml

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

相关文章

docker 可用镜像服务地址(2024.10.31亲测可用)

1.错误 Error response from daemon: Get “https://registry-1.docker.io/v2/” 原因&#xff1a;镜像服务器地址不可用。 2.可用地址 编辑daemon.json&#xff1a; vi /etc/docker/daemon.json内容修改如下&#xff1a; {"registry-mirrors": ["https://…

Git (推送到远端仓库)

目录 一、在 gitee 上创建一个仓库 二、将项目推送到远程仓库 三、解释推送命令 一、在 gitee 上创建一个仓库 操作如下&#xff1a; 二、将项目推送到远程仓库 这里例举新的项目推送到远程仓库的例子&#xff1a; 打开仓库查看&#xff1a; 三、解释推送命令 添加远程仓库…

opencv学习笔记(6):图像预处理(直方图、图像去噪)

3.直方图 直方图是用来表现图像中亮度分布的&#xff0c;给出的是图像中某个亮度或者某个范围亮度下共有几个像素&#xff0c;即统计一幅图某个亮度像素的数量。 直方图不能反映某一灰度值像素在图像中的位置&#xff0c;失去了图像的空间信息。图像直方图由于其计算代价较小&a…

《双指针篇》---移动零

题目传送门 这道题可以归类为 数组划分/数组分块 。 题目制定了一个规则&#xff0c;我们可以在这个规则下&#xff0c;将数组划分为若干个区间。 这道题让我们把所有非零元素移动到左边。所有零元素移动到右边。 将数组划分为&#xff1a; 左区间非0&#xff1b; 右区间&…

OpenHarmony、HarmonyOS、HarmonyNext互相兼容吗?

1&#xff0c;三者之间的关系 OpenHarmony&#xff1a;开源底层。HarmonyOS&#xff1a;闭源手机系统&#xff0c;兼容安卓生态。HarmonyOS NEXT&#xff1a;纯血鸿蒙&#xff0c;不兼容安卓。 上一篇文章简单介绍过&#xff0c;就不再多说了&#xff0c;这里说一下HarmonyOS …

Camera学习笔记(202410)

课程&#xff1a;CameraX&#xff1a;面向开发者的摄像头支持库 链接&#xff1a;CameraX&#xff1a;面向开发者的摄像头支持库_哔哩哔哩_bilibili 课程时长&#xff1a;28:00 学习时间&#xff1a;2024-10-29 概述&#xff1a;2019年Android CameraX的发布会 个人感觉&a…

Django入门教程——用户管理实现

第六章 用户管理实现 教学目的 复习数据的增删改查的实现。了解数据MD5加密算法以及实现模型表单中&#xff0c;自定义控件的使用中间件的原理和使用 需求分析 系统问题 员工档案涉及到员工的秘密&#xff0c;不能让任何人都可以看到&#xff0c;主要是人事部门进行数据的…

BugKu练习记录:矛盾

题目&#xff1a; $num$_GET[num]; if(!is_numeric($num)) { echo $num; if($num1) echo flag{**********}; }关键在于绕过is_numeric&#xff0c;PHP中字符串与数字弱比较&#xff0c;会将字符串转换为数字&#xff0c;截至到非数字字符&#xff0c;如果第一个字符就是非数字…

安宝特分享 | AR技术引领:跨国工业远程协作创新模式

在当今高度互联的工业环境中&#xff0c;跨国合作与沟通变得日益重要。然而&#xff0c;语言障碍常常成为高效协作的绊脚石。安宝特AR眼镜凭借其强大的多语言自动翻译和播报功能&#xff0c;正在改变这一局面&#xff0c;让远程协作变得更加顺畅。 01 多语言翻译优势 安宝特A…

逗号运算符应用举例

在main.cpp里输入程序如下&#xff1a; #include <iostream> //使能cin(),cout(); #include <iomanip> //使能setbase(),setfill(),setw(),setprecision(),setiosflags()和resetiosflags(); //setbase( char x )是设置输出数字的基数,如输出进制数则用set…

vxe-table v4.8+ 与 v3.10+ 虚拟滚动支持动态行高,虚拟渲染更快了

Vxe UI vue vxe-table v4.8 与 v3.10 解决了老版本虚拟滚动不支持动态行高的问题&#xff0c;重构了虚拟渲染&#xff0c;渲染性能大幅提升了&#xff0c;行高自适应和列宽拖动都支持&#xff0c;大幅降低虚拟渲染过程中的滚动白屏&#xff0c;大量数据列表滚动更加流畅。 自适…

ICPC区域赛成都站【赛后回顾+总结】

传送门 前言赛后总结赛后回顾赛后感悟 前言 首先&#xff0c;这是本人本赛季第一场XCPC区域赛&#xff0c;也是本人算竞生涯中第一场XCPC区域赛&#xff08;之前只打过邀请赛和省赛&#xff09;。 赛后总结 然后赛后总结一下&#xff1a;我队天崩开局&#xff0c;我队出师不利…

c盘满了怎么清理垃圾而不误删?6招轻松清理C盘,快来试试

c盘满了怎么清理垃圾而不误删&#xff1f;相信平时工作生活中离不开电脑&#xff0c;随着使用电脑时间就了&#xff0c;C 盘的空间会不断被占据&#xff0c;进而致使系统运行变得迟缓&#xff0c;甚至出现卡顿现象。因此&#xff0c;定期清理 C 盘的是非常重要的。很多电脑小白…

excel的宏1

1宏和vba visual basic for applications 一种编程语言 2vba编写一系列指令的程序&#xff0c;就是宏 3完成重复性的数据任务 点击开发工具 使用设置的宏之后表格的变化 excel帮忙编写了一个代码 以上为自动编写的代码

Swarm-LIO: Decentralized Swarm LiDAR-inertial Odometry论文翻译

文章目录 前言一、介绍二、相关工作三、方法A. 问题表述B. 框架概述C. 群体系统的初始化D. 去中心化激光雷达-惯性状态估计 四. 实验A. 室内飞行B. 退化环境飞行C. 去中心化部署 五. 结论和未来工作 前言 原文&#xff1a;原文 准确的自我状态和相对状态估计是完成群体任务的关…

光耦合器的关键作用和创新---腾恩科技

光耦合器或光隔离器已成为电路中必不可少的器件&#xff0c;它允许信号在无需直接电接触的情况下跨不同电压域传输。这种隔离能力对于保护低压元件免受高压电路的潜在损坏至关重要。本文将仔细研究光耦合器在当今技术中发挥的独特作用&#xff0c;并探讨其在各种应用中不断扩展…

linux:回车换行+进度条+git理解与使用以及如何解决免密码push问题

目录 特殊符号 Linux小程序---进度条 1.\n和\r的理解 2.缓冲区 3.设计简单的倒计时 4.设计简单的进度条 git-版本控制器 1.理解什么是版本控制器? 2.git的使用 3.git的其他说明 总结上传过程 特殊符号 1.(取消显化) 的作用:执行指令,但指令本身不会显化; 举个例子:我…

vscode摸鱼学习插件开发

不知道大家在摸鱼的时候&#xff0c;会不会想要学习&#xff1f; 或者有没有考公人&#xff0c;下班要学习的&#xff1f; 上班时间摸鱼&#xff0c;下班时间不够学习&#xff1f; 为此&#xff0c;我决定开发一个vscode插件&#xff0c;来刷粉笔题 粉笔插件名称&#xff1a;…

如何解决RabbitMQ消息的重复消费问题

什么情况下会导致消息的重复消费——在消费者还没成功发送自动确认机制时发生&#xff1a; 网络抖动消费者挂了 解决方案 每条消息设置一个唯一的标识id幂等方案&#xff1a;【Redis分布式锁、数据库锁&#xff08;悲观锁、乐观锁&#xff09;】 面试官&#xff1a;如何解决…

Kafka 与传统 MQ 消息系统之间有三个关键区别?

大家好&#xff0c;我是锋哥。今天分享关于【Kafka 与传统 MQ 消息系统之间有三个关键区别&#xff1f;】面试题&#xff1f;希望对大家有帮助&#xff1b; Kafka 与传统 MQ 消息系统之间有三个关键区别&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 …