C++ 使用 new 创建二维数组
1. 直接创建
C++ 使用 new 创建二维数组最直接的方法就是 new T[M][N]
。返回的指针类型是 T (*)[N]
,它是指向数组的指针,可以直接使用数组下标形式访问元素。释放内存直接使用delete[]
。示例代码:
#include <iostream>
class A
{
public:
A()
{
std::cout << "A::A" << std::endl;
}
~A()
{
std::cout << "A::~A" << std::endl;
}
int x;
};
int main()
{
A (*p)[3] = new A[2][3];
delete[] p;
}
执行结果:
A::A
A::A
A::A
A::A
A::A
A::A
A::~A
A::~A
A::~A
A::~A
A::~A
A::~A
可以看到 A 的构造函数和析构函数正常执行。如果觉得 T (*)[N]
繁琐,可以直接使用 auto p = new T[M][N]
。三维数组甚至更高维数组都可以使用这种方法。例如,三维数组使用 new T[M][N][O]
进行创建,依旧使用 delete[] p
进行释放。
为什么可以这样写?因为这种多维数组和普通的多维数组都是通过一维数组实现的。例如,int a[6][8]
,实际上编译器会转化为 int b[6 * 8]
一维数组。然后每次访问二维数组 a[i][j]
相当于访问 b[i * 8 + j]
。从二维、三维数组的转化过程中可以发现一些规律。
T a[M][N] --> T b[M * N], a[i][j] --> b[i * N + j]
T a[M][N][O] --> T b[M * N * O], b[i][j][k] --> b[i * N * O + j * O + k]
编译器进行下标转换时,并没有用到第 0 维的大小,而其它维的大小都是必须的。这也就是为什么下面代码能正确执行。
int a[2][3];
int (*p)[3] = a;
由于多维数组本质上是一维数组,所以释放内存都是 delete[] p
,而没有奇怪的 delete[][]
语法。
2. 借助指针数组
还有一种方法就是先 new T*[M]
创建一个指针数组,其每个元素保存每一行的首个元素的地址,再使用 new T[N]
创建每一行。示例代码如下:
A** p = new A*[2];
for (int i = 0; i < 2; ++i) {
p[i] = new A[3];
}
for (int i = 0; i < 2; ++i) {
delete[] p[i];
}
delete[] p;
这种方法非常繁琐,首先 new T*[M]
不能写成 new (T(*)[M])
,因为它是指针数组而不是数组指针。其次,需要对每一行调用 new T[N]。释放内存时,要先使用 delete[]
释放每一行,再调用 delete[]
释放数组指针。这几个步骤一步都不能错,不然就出现野指针或者内存泄漏。这段代码我也是用 Address Sanitizer 和 Leak Sanitizer 检查一遍才写对。
这种方法唯一的好处就是可以创建交错数组(Jagged Array),也就是每一行的大小不一样。例如:
A **p = new A *[2];
p[0] = new A[3];
p[1] = new A[4];
for (int i = 0; i < 2; ++i)
{
delete[] p[i];
}
delete[] p;
3. 借助 std::vector
可以用 std::vector 对上面这种方法进行包装,使其更加易用。示例代码如下:
std::vector<std::vector<int>> v{ std::vector<int>(3), std::vector<int>(4) };
std::cout << v[0].size() << " " << v[1].size() << std::endl;
这段代码创建了一个二维数组,第 0 行有 3 个元素,第 1 行有 4 个元素。这种方法既能创建交错数组,也不需要手动释放内存。
C++ 使用 new 创建二维数组的更多相关文章
- C语言 动态创建二维数组
/*C语言 如何动态创建二维数组 转化为一维数组申请数组,创建和释放都比较简单 */ #include <stdlib.h> #include <stdio.h> #inclu ...
- Python创建二维数组(关于list的一个小坑)
0.目录 1.遇到的问题 2.创建二维数组的办法 3.1 直接创建法 3.2 列表生成式法 3.3 使用模块numpy创建 1.遇到的问题 今天写Python代码的时候遇到了一个大坑,差点就耽误我交作 ...
- c/c++ 图的创建(二维数组法)
c/c++ 图的创建(二维数组法) 图的概念 图由点和线组成 知道了图中有多少个点,和哪些点之间有线,就可以把一张图描绘出来 点之间的线,分有方向和无方向 创建图 创建图,实际就是创建出节点,和节点之 ...
- C#中创建二维数组,使用[][]和[,]的区别
C#中,我们在创建二维数组的时候,一般使用arr[][]的形式,例如 int[][] aInt = new int[2][]; 但声明二维数组还有一种方法,是使用arr[,]的形式.两者有什么区别呢? ...
- c++ 用new创建二维数组~创建指针数组【转】
#include <iostream> using namespace std; void main() { //用new创建一个二维数组,有两种方法,是等价的 //一: ] = ][]; ...
- c++用vector创建二维数组
1 vector二维数组的创建和初始化 std::vector <int> vec(10,90); //将10个一维动态数组初始为90std::vector<std::vector& ...
- stl vector创建二维数组
vector<vector<); for (auto it = v.begin(); it != v.end(); it++) { ; (*it).reserve();//预留空间为5,但 ...
- c++中创建二维数组的几种方法
一.用new申请内存空间 int **dp=new int*[n];//动态申请二维数组nxm ;i<n;++i){ dp[i]=new int[m]; } 二.用malloc申请内存空间 ; ...
- typescript 创建二维数组
private mouseView: Mouse private mouseArray: Array<Array<any>> = new Array<Array<a ...
- 【转】C++动态创建二维数组,二维数组指针
原作者博客:蒋国宝的IT技术博客 今天完成一道题目需要自己用指针创建一个二维的数组,不得不承认指针的确是恶心. int **result; ; ; result = new int*[row]; ; ...
随机推荐
- Dapr v1.9.0 版本已发布
Dapr是一套开源.可移植的事件驱动型运行时,允许开发人员轻松立足云端与边缘位置运行弹性.微服务.无状态以及有状态等应用程序类型.Dapr能够确保开发人员专注于编写业务逻辑,而不必分神于解决分布式系统 ...
- python视频与帧图片的相互转化,以及查看视频分辨率
1.拆分视频为帧图片 import cv2 def video2frame(videos_path,frames_save_path,time_interval): vidcap = cv2.Vide ...
- The XOR Largest Pair(字典树)
题目描述 在给定的 N 个整数 A1,A2,-,AN 中选出两个进行异或运算,得到的结果最大是多少? 输入格式 第一行一个整数 N. 第二行 N 个整数 Ai. 输出格式 一个整数表示答案. 样例 ...
- nginx 客户端返回499的错误码
我们服务器客户端一直有返回错误码499的日志,以前觉得比例不高,就没有仔细查过,最近有领导问这个问题,为什么耗时只有0.0几秒,为啥还499了?最近几天就把这个问题跟踪定位了一下,这里做个记录 网络架 ...
- 测试开发mysql性能调优总结(一)
测试开发mysql性能调优总结 mysql在创建表的时候,对每个字段选择合适的数据类型很重要! 根据个人的经验总结: 整数类型选择 INT小数类型选择 DECIMAL字符串类型选择 TEXT日期时间选 ...
- OpenHarmony移植案例: build lite源码分析之hb命令__entry__.py
摘要:本文介绍了build lite 轻量级编译构建系统hb命令的源码,主要分析了_\entry__.py文件. 本文分享自华为云社区<移植案例与原理 - build lite源码分析 之 hb ...
- echarts标题(title)配置
var option = { //标题 title : { show:true,//显示策略,默认值true,可选为:true(显示) | fa ...
- AI音乐创作,让每一个人都成为音乐家
从录音带.MP3到专业的耳机.音箱,随着音乐消费方式的不断升级,音乐创作的专业"门槛"也在AI技术的加持下逐渐大众化,创作者的创新设计.创作频率也在持续增强,能降低创作门槛且智能化 ...
- Day11.2:标签的使用
标签的使用 当我们在嵌套语句中,例如当我们在for的嵌套循环语句中,想要终止或重新开始当前循环以外的循环的时候,单独仅靠break和continue和还不够,需要在我们想要作用的循环语句处加上一个标签 ...
- C#程序自启动
在窗体加载事件里面加入下述代码: //设置开机自启动 RegistryKey registryKey = Registry.CurrentUser.OpenSubKey ("SOFTWARE ...