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

C++ 动态内存

         C++ 程序中的内存分为栈和堆两个部分:

  • 栈:在函数内部声明的所有变量都将占用栈内存;
  • 堆:这是程序中未使用的内存,在程序运行时可用于动态分配内存。

         堆与栈的详细请参考:一文读懂堆与栈的区别_堆和栈的区别_恋喵大鲤鱼的博客-CSDN博客

         由于很多时候无法提前预知存储某个定义变量中的特定信息需要多少内存,所需内存的大小需要在运行时才能确定。因此,在 C++ 中可以使用 new 运算符为给定类型的变量在运行时分配堆内的内存,并返回所分配空间的地址。当不再需要动态分配的内存空间时,使用 delete 运算符释放之前由 new 运算符分配的内存。

new 和 delete 运算符

         使用 new 运算符动态分配任意数据类型内存的通用语法:

new Data_Type;

         Data_Type 是包括数组在内的任意内置的数据类型,也可以是包括类或结构在内的自定义的任何数据类型。例如,定义一个指向 double 类型的指针,然后请求内存,该内存在执行时被分配:

double* pvalue = NULL;   // 初始化为 null 的指针
pvalue  = new double;    // 为变量请求内存
//也可以直接分配并赋值给指针:double* pvalue = new double;

         当不再需要已经动态分配内存的变量时,使用 delete 操作符释放它所占用的内存(注意:pvalue指针变量本身并没有被销毁,销毁的是它指向的变量),如下所示: 

delete pvalue;  // 释放 pvalue 所指向的内存

         如果自由存储区已被用完,可能无法成功分配内存。所以建议检查 new 运算符是否返回 NULL 指针,并采取以下适当的操作:

double* pvalue  = NULL;
if(!(pvalue  = new double))  // 返回 NULL 指针
{cout << "Error: out of memory." <<endl;exit(1);
}

         演示使用 new 和 delete 运算符:

#include <iostream>
using namespace std;int main ()
{double* pvalue  = NULL;     // 初始化为 NULL 的指针pvalue  = new double;       // 为变量请求内存*pvalue = 10086.11;         // 在分配的地址存储值cout << "Value of pvalue : " << *pvalue << endl;delete pvalue;              // 释放内存return 0;
}

         执行结果如下:

Value of pvalue :10086.1

         malloc() 函数在 C++ 中仍然存在,但建议尽量不要使用 malloc() 函数。new 与 malloc() 函数相比,其主要的优点是,new 不只是分配了内存,它还创建了对象。

数组的动态内存分配

一维数组

         假设为一个能存储 20 个字符的一维数组动态分配内存,如下所示:

char* pvalue = NULL;      // 初始化为 null 的指针
pvalue = new char [20];   // 为变量请求内存

         删除创建的数组,语句如下:

delete [] pvalue;   // 删除 pvalue 所指向的数组

二维数组

         例如,下面是一个二维数组a[3][4],包含 3 行和 4 列:

         二维数组array[m][n]:

/* 假定数组array[m][n]第一维长度(行)为 m,第二维长度(列)为 n */
int** array;               // 声明一个指向int类型指针的指针
array = new int *[m];      // 分配m个存储int*类型的空间,array指向第一个存储int*的地址/* 为每一行分配空间 */
for( int i=0; i<m; i++ )   
{array[i] = new int [n];
}/* 释放每一行 */
for( int i=0; i<m; i++ )
{delete [] array[i];
}delete [] array;       

         实例:

#include<iostream>
using namespace std;int main()
{int **a;int i,j;a = new int *[4];for(i=0;i<4;i++){a[i]=new int [8];}for(i=0;i<4;i++)   // 初始化数组{for(j=0;j<8;j++){a[i][j]=((i+1)*(j+1));}}for(i=0;i<4;i++)   // 打印数组数据{for(j=0;j<8;j++){			cout<<a[i][j]<<"\t";if((j==7)&&(i!=3))   // 每行8个,再换行cout<<endl; }}for(i=0;i<4;i++)   // 释放分配的内存{delete [] a[i];}delete [] a;return 0;
}

         执行结果如下:

1       2       3       4       5       6       7       8
2       4       6       8       10      12      14      16
3       6       9       12      15      18      21      24
4       8       12      16      20      24      28      32

三维数组

/* 假定数组第一维为 m, 第二维为 n, 第三维为 h */ 
int ***array;
array = new int **[m];for( int i=0; i<m; i++ )
{array[i] = new int *[n];for( int j=0; j<n; j++ ){array[i][j] = new int [h];}
}for( int i=0; i<m; i++ )   //释放内存
{for( int j=0; j<n; j++ ){delete[] array[i][j];}delete [] array[i];
}delete[] array;

         实例:

#include<iostream>
using namespace std;int main()
{int i,j,k;        // a[2][3][4]int ***a;a = new int **[2];for(i=0;i<2;i++) {a[i]=new int *[3];for(j=0;j<3;j++){a[i][j]=new int [4];}}for(i=0;i<2;i++)  //初始化,并输出{for(j=0;j<3;j++){for(k=0;k<4;k++){a[i][j][k] = i+j+k;cout<<a[i][j][k]<<" ";}cout<<endl;						}cout<<endl;}for(i=0;i<2;i++)  //释放内存{for(j=0;j<3;j++){delete [] a[i][j];}			}for(i=0;i<2;i++){delete [] a[i];}delete [] a;return 0;
}

         执行结果如下:

0 1 2 3
1 2 3 4
2 3 4 5

1 2 3 4
2 3 4 5
3 4 5 6
 

         补充:由于对象没有析构函数(destructor),“ delete [] p ”和 “ delete p ” 对于像 int/char/long/int*/struct 等简单数据类型的释放没有太大区别。但对于C++ 对象数组,就不同了:

  • delete a;     仅释放了a指针指向的全部内存空间 ,但是只调用了a[0]对象的析构函数,其他分配的内存空间将不能释放,从而造成内存泄漏;
  • delete [] a;  调用使用类对象的析构函数释放用户自己分配内存空间,并释放了a指针指向的全部内存空间。

对象的动态内存分配

         对象与简单的数据类型没有什么不同,如下所示,为一个包含3个 Box 对象的数组分配内存,构造函数将被调用 4 次。当删除这些对象时,析构函数也将被调用相同的次数:

#include<iostream>
using namespace std;class Box
{
public:Box(){cout<<"调用构造函数!"<<endl;}~Box(){cout<<"调用析构函数!"<<endl;}
};int main()
{Box* BoxArray = new Box[3];delete [] BoxArray;return 0;
}

         执行结果如下:

调用构造函数!
调用构造函数!
调用构造函数!
调用析构函数!
调用析构函数!
调用析构函数!

new 和 malloc 的区别

         new 的功能是在堆区新建一个对象,并返回该对象的指针。 "新建对象" 的意思就是将调用该类的构造函数,因为如果不构造的话,就不能称之为一个对象。

         malloc 只是机械的分配一块内存,用 mallco 在堆区创建一个对象不会调用构造函数。严格说来用 malloc 不能算是新建了一个对象,只能说是分配了一块与该类对象匹配的内存而已,然后强行把它解释为 “这是一个对象”,因此,也不存在调用构造函数的说法。

         同样的,用 delete 去释放一个堆区的对象,会调用该对象的析构函数。

         用 free 去释放一个堆区的对象,不会调用该对象的析构函数。

         实例:

#include <iostream>
#include <malloc.h> // 需要用到malloc()函数using namespace std;class Test
{
private:int num1;int num2;
public:Test(){num1 = 10;num2 = 20;}		void Print(){cout<<num1<<"\t" <<num2<<endl;		}
};int main()
{/****用malloc()函数在堆区分配一块内存空间,然后用强制类型转换将该块内存空间*解释为是一个Test类对象,但不会调用Test的默认构造函数	  */ Test* pObject1 = (Test*)malloc(sizeof(Test));pObject1->Print();/* 用new在堆区创建一个Test类的对象,会调用Test类的默认构造函数 */Test* pObject2 = new Test;pObject2->Print();return 0;
}

         由于pObject1没有调用Test类的默认构造函数,所以在pObject1所指的对象中,num1与num2都是malloc()分配地址上原有的垃圾值,并非是由构造函数定义的初始值(10 or 20)。而pObject2所指的对象中,num1与num2显然是经过了构造后的值,执行结果如下:

1922960 0
10      20

相关文章:

C++ 动态内存

C 程序中的内存分为栈和堆两个部分&#xff1a; 栈&#xff1a;在函数内部声明的所有变量都将占用栈内存&#xff1b;堆&#xff1a;这是程序中未使用的内存&#xff0c;在程序运行时可用于动态分配内存。 堆与栈的详细请参考&#xff1a;一文读懂堆与栈的区别_堆和栈的区别_恋…...

swagger 接口测试,用 python 写自动化时该如何处理?

在使用Python进行Swagger接口测试时&#xff0c;可以使用requests库来发送HTTP请求&#xff0c;并使用json库和yaml库来处理响应数据。以下是一个简单的示例代码&#xff1a; import requests import json import yaml# Swagger API文档地址和需要测试的接口路径 swagger_url …...

QT使用QXlsx实现Excel图片与图表操作 QT基础入门【Excel的操作】

构建图表数据 /// 构建图表数据for (int i = 1; i < 10; ++i) {mxlsx.write(i, 1, i * i * i); // A1:A9mxlsx.write(i, 2, i * i); // B1:B9mxlsx.write(i, 3, i * i - 1); // C1:C9} 需要包含头文件 #include "xlsxchart.h" 1. 饼状图 Chart *pieChart = mxlsx.…...

【Python常用函数】一文让你彻底掌握Python中的numpy.clip函数

大数据时代的到来,使得很多工作都需要进行数据挖掘,从而发现更多有利的规律,或规避风险,或发现商业价值。而大数据分析的基础是学好编程语言。本文和你一起来探索Python中的clip函数,让你以最短的时间明白这个函数的原理。也可以利用碎片化的时间巩固这个函数,让你在处理…...

Matlab(GUI程式设计)

目录 1.MatlabGUI 1.1 坐标区普通按钮 1.1.1 对齐组件 1.1.2 按钮属性 1.1.3 脚本说明 1.1.4 选择呈现 1.3 编译GUI程序 在以前的时候&#xff0c;我们的电脑还是这样的 随着科技的不断进步&#xff0c;我们的电脑也发生着翻天覆地的改变1990s&#xff1a; 在未来&#xff0c…...

Numpy数组(随时更新)

一、Numpy数组对象的重要属性 #导入库 import numpy as npdata np.arange(12).reshape(4,3)data2 np.arange(24).reshape(3,4,2) #ndim维度个数data.ndimdata2.ndim #shape形状几行几列 数组的维度data.shapedata2.shape#size数组的总个数data.sizedata2.size #dtype数组元素的…...

Spring Cloud--从零开始搭建微服务基础环境【三】

&#x1f600;前言 本篇博文是关于Spring Cloud–从零开始搭建微服务基础环境【三】&#xff0c;希望你能够喜欢 &#x1f3e0;个人主页&#xff1a;晨犀主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是晨犀&#xff0c;希望我的文章可以帮助到大家&#xff0c;…...

HDFS文件的读写流程

Hadoop HDFS的读写文件流程 HDFS写文件流程 客户端通过Distributed FileSystem模块向NameNode请求上传文件&#xff08;hadoop fs -put 文件名 文件路径 &#xff09; 判断该客户端是否有写入权限NameNode检查目标文件是否已存在&#xff0c;父目录是否存在。 NameNode返回是…...

SpringCloudGateway集成SpringDoc

SpringCloudGateway集成SpringDoc 最近在搞Spring版本升级&#xff0c;按客户要求升级Spring版本&#xff0c;原来用着SpringBoot 2.2.X版本&#xff0c;只需要升级SpringBoot 2.X最新版本也就可以满足客户Spring版本安全要求&#xff0c;可是好像最新的SpringBoot 2.X貌似也不…...

ArcGIS将两个相同范围但不同比例或位置的矢量数据移动到相同位置

有两个市图层&#xff0c;一个是正确经纬度的市行政范围图层&#xff0c;另一个是其他软件导出获取的不正确经纬度信息或缺失信息。 如果单纯的依靠移动图层&#xff0c;使不正确的移动到正确位置需要很久。尝试定义投影等也不能解决。 使用ArcMap 的空间校正工具条&#xff…...

MySQL编写建表语句,如何优雅处理创建时间与更新时间

在 MySQL 中&#xff0c;可以使用 TIMESTAMP 或者 DATETIME 数据类型来存储日期和时间信息&#xff0c;并结合默认值和触发器来实现自动更新 createTime 和 updateTime 字段。 以下是一个示例建表语句&#xff0c;演示如何设置自动更新的 createTime 和 updateTime 字段&#…...

NetSuite as OIDC Provider 演示

书接上回。上次谈了借助第三方身份认证服务SSO登录NetSuite。 NetSuite OIDC、SAML SSO 演示_NetSuite知识会的博客-CSDN博客NetSuite的SSO的策略&#xff1a;第三方的身份认证服务商NetSuite as OIDC Provider。本文演示前者。https://blog.csdn.net/remottshanghai/article/…...

webrtc sdp各字段含义

WebRTC使用Session Description Protocol&#xff08;SDP&#xff09;实现传输协议的协商和描述。以下是SDP中常见的字段及其含义&#xff1a; v&#xff1a;协议版本号o&#xff1a;会话创建者的标识符、会话ID、和会话版本号s&#xff1a;会话名称t&#xff1a;会话时间描述…...

Docker 常用服务 安装使用 教程

Docker安装常用服务 1、 安装mysql # 1.拉取mysql镜像到本地 docker pull mysql:tag (tag不加默认最新版本) # 2.运行mysql服务 docker run --name mysql -e MYSQL_ROOT_PASSWORDroot -d mysql:tag --没有暴露外部端口外部不能连接 docker run --name mysql -e MYSQL_ROOT_PAS…...

Java String类(2)

String方法 字符串拆分 可以将一个完整的字符串按照指定的分隔符划分为若干个子字符串 相关方法如下&#xff1a; 方法功能String[ ] split(String regex)//以regex分割将字符串根据regex全部拆分String[ ] split(String regex, int limit)将字符串以指定的格式&#xff0c;拆…...

基于图像切割计算轨迹相似度

目录 背景思路与核心代码数值实验优缺点分析参考文献 背景 在前面2文&#xff0c;我们分别讨论了利用夹角余弦来计算轨迹相似度和利用缓冲原理来计算轨迹相似度两种方法&#xff0c;前者可以作为一个baseline提供参考&#xff0c;后者的计算更符合人们的感官和事实&#xff0c…...

Day49|leetcode 121. 买卖股票的最佳时机、122.买卖股票的最佳时机II

leetcode 121. 买卖股票的最佳时机 题目链接&#xff1a;121. 买卖股票的最佳时机 - 力扣&#xff08;LeetCode&#xff09; 视频链接&#xff1a;动态规划之 LeetCode&#xff1a;121.买卖股票的最佳时机1_哔哩哔哩_bilibili 题目概述 给定一个数组 &#xff0c;它的第 个元…...

【项目经验】:elementui表格中表头的多选框换成文字

一.项目需求 表格可以多选&#xff0c;表头都是汉字。。。。类似于这种 二.实现功能 用到的方法 Table Attributes 参数说明类型可选值默认值header-cell-class-name表头单元格的 className 的回调方法&#xff0c;也可以使用字符串为所有表头单元格设置一个固定的 className。…...

【LeetCode】剑指 Offer <二刷>(4)

目录 题目&#xff1a;剑指 Offer 09. 用两个栈实现队列 - 力扣&#xff08;LeetCode&#xff09; 题目的接口&#xff1a; 解题思路&#xff1a; 代码&#xff1a; 过啦&#xff01;&#xff01;&#xff01; 题目&#xff1a;剑指 Offer 10- I. 斐波那契数列 - 力扣&am…...

CentOS7查看和关闭防火墙

CentOS 7.0默认使用的是firewall作为防火墙 查看防火墙状态 firewall-cmd --state1 停止firewall systemctl stop firewalld.service1 禁止firewall开机启动 systemctl disable firewalld.service 1 转自&#xff1a;CentOS 6和CentOS 7防火墙的关闭 Centos7开放及查看…...

Linux链表操作全解析

Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表&#xff1f;1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建

制造业采购供应链管理是企业运营的核心环节&#xff0c;供应链协同管理在供应链上下游企业之间建立紧密的合作关系&#xff0c;通过信息共享、资源整合、业务协同等方式&#xff0c;实现供应链的全面管理和优化&#xff0c;提高供应链的效率和透明度&#xff0c;降低供应链的成…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?

在建筑行业&#xff0c;项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升&#xff0c;传统的管理模式已经难以满足现代工程的需求。过去&#xff0c;许多企业依赖手工记录、口头沟通和分散的信息管理&#xff0c;导致效率低下、成本失控、风险频发。例如&#…...

STM32标准库-DMA直接存储器存取

文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA&#xff08;Direct Memory Access&#xff09;直接存储器存取 DMA可以提供外设…...

C# 类和继承(抽象类)

抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍

文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结&#xff1a; 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析&#xff1a; 实际业务去理解体会统一注…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)

🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...

MySQL 8.0 事务全面讲解

以下是一个结合两次回答的 MySQL 8.0 事务全面讲解&#xff0c;涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容&#xff0c;并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念&#xff08;ACID&#xff09; 事务是…...

leetcode_69.x的平方根

题目如下 &#xff1a; 看到题 &#xff0c;我们最原始的想法就是暴力解决: for(long long i 0;i<INT_MAX;i){if(i*ix){return i;}else if((i*i>x)&&((i-1)*(i-1)<x)){return i-1;}}我们直接开始遍历&#xff0c;我们是整数的平方根&#xff0c;所以我们分两…...

StarRocks 全面向量化执行引擎深度解析

StarRocks 全面向量化执行引擎深度解析 StarRocks 的向量化执行引擎是其高性能的核心设计&#xff0c;相比传统行式处理引擎&#xff08;如MySQL&#xff09;&#xff0c;性能可提升 5-10倍。以下是分层拆解&#xff1a; 1. 向量化 vs 传统行式处理 维度行式处理向量化处理数…...