C++动态分配(new)二维数组的若干方法

写在前面

之前刷动态规划的题目,多需要用到二维数组(也许后面再优化成一维)。如果每次都按照给定数的范围直接声明为全局二维数组变量,又总觉得的不够优雅。查阅了一些网上的资料后,总结了一些使用方法,就写下这篇博文用以记录。

方法1——动态分配(new)一维数组,再强制类型转换为二维(个人使用,推荐指数:⭐⭐⭐⭐)

直接看例子

/** 假设需要根据两个string的长度建立二维数组 */
const int sz1 = str1.size(); 
const int sz2 = str2.size(); 

/** 动态分配内存 */
auto f = new int[sz1 * sz2];
auto dp = (int (*)[sz2])f;

/** 这里放置自己制造bug的操作*/
// abaabaaba, 直接dp[i][j]使用即可

/** 制造完了别忘记释放栈空间 */
delete[] f;
f = nullptr;
dp = nullptr;

注意,auto dp = (int (*)[sz2]f这条语句,sz2的大小一定要是后面使用二维数组时最低维的大小
如果按照上面的类型转换方式,下面这样写会出现bug(注意sz1和sz2的顺序):

for (int i = 0; i < sz2; ++i)
  for (int j = 0; j < sz1; ++j)
    // do something; 
    /** 其实大概率你啥也do不了,程序跑飞了 */

这个方法优点和缺点都很明显,灵活、完全和使用全局二维数组方法一样,且释放内存简单,但是使用存在危险性。如果觉得自己把握不住,建议先考虑其他方法。


另外,请读者考虑一下,可以使用如下的二重指针代替一维数组的指针进行类型转换吗?

auto f = new int[sz1 * sz2];
auto dp = (int **)f; /** 二重指针真的可以吗?*/

若觉得可行的话,可能对二维数组和二重指针的理解出现了偏差。试想,我们按照dp存储的地址值a去寻址,得到地址a中存储的值b,再按照值b去寻址的话会发生什么?(本例中,b的值的根本不是地址,而是数组的值!)

C++动态分配(new)二维数组的若干方法

我们思考后也不难理解,为什么声明二维数组的形参类型或者是强制类型转换时,一定要正确指定最低维的大小。

方法2——分配一维数组,以二维数组的方式使用(推荐指数:⭐⭐⭐)

其实如果不是非要追求“传统”的使用二维数组的方式,也可以不用强制类型转换的方法。

只需要把握一点:二维数组的所有元素,在内存中是连续排列的。

那么我们可以按照如下的方式使用分配的二维数组:

/** 假设需要根据两个string的长度建立二维数组 */
const int sz1 = str1.size(); 
const int sz2 = str2.size(); 

/** 动态分配内存 */
auto f = new int[sz1 * sz2];

/** 给每个元素赋值 */
for (int i = 0, idx = 1; i < sz1; ++i)
    for (int j = 0; j < sz2; ++j, ++idx)
        f[i * sz2 + j] = idx; /** 相当于 arr[i][j] = idx; */

/** 别忘记释放堆空间 */
delete[] f;
f = nullptr;

与方法一大同小异,因此注意事项也一样,注意f[i * sz2 + j]中sz2是最低维的大小。

方法3——多次动态分配(也需要多次释放)(推荐指数:⭐⭐)

简单说,就是动态分配一维数组,然后把这些数组的指针存储到一个数组元素为一维数组的数组中。
代码如下:

/** 假设需要根据两个string的长度建立二维数组 */
const int sz1 = str1.size(); 
const int sz2 = str2.size(); 

/** 分配一个数组元素为一维数组的数组 */
auto dp = new int *[sz1];

/** 给数组每个元素赋值 */
for (int i = 0; i < sz1; ++i)
  dp[i] = new int[sz2];

/** 这里放置自己制造bug的操作*/
// abaabaaba

/** 制造完了别忘记释放堆空间 */
for (int i = 0; i < sz1; ++i)
  delete[] dp[i];

delete[] dp;

注意最后要先释放元素的内存。

(小声说,应该很少有人用这种方法?)

方法4——使用vector(推荐指数:⭐⭐⭐⭐⭐)

前面的几种方法多少是不太 idiomatic C++,最后当然要请出我们的STL。

没什么说的,直接看代码:

vector<vector<int> > dp(str1.length(), vector<int>(str2.length(), 0));

优点是不用再担心内存释放的问题,并且vector有很多方便的成员函数可以使用。

另外,在刷题的时候如果要判断二维vector是否为空,可以使用如下语句:

if (dp.empty() || dp[0].empty()) 
  return ;

原文链接:https://www.cnblogs.com/yang5sui/p/17311997.html

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++动态分配(new)二维数组的若干方法 - Python技术站

(0)
上一篇 2023年4月17日
下一篇 2023年4月17日

相关文章

  • 【Visual Leak Detector】配置项 SelfTest

    说明 使用 VLD 内存泄漏检测工具辅助开发时整理的学习笔记。本篇介绍 VLD 配置文件中配置项 SelfTest 的使用方法。 同系列文章目录可见 《内存泄漏检测工具》目录 目录 说明 1. 配置文件使用说明 2. 设置是否开启泄漏自检 2.1 测试代码 2.2 SelfTest = off 时的输出 2.3 SelfTest = on 时的输出 2.4 …

    C++ 2023年4月18日
    00
  • 【Visual Leak Detector】配置项 SkipCrtStartupLeaks

    说明 使用 VLD 内存泄漏检测工具辅助开发时整理的学习笔记。本篇介绍 VLD 配置文件中配置项 SkipCrtStartupLeaks 的使用方法。同系列文章目录可见 《内存泄漏检测工具》目录 目录 说明 1. 配置文件使用说明 2. 设置是否忽略启动代码引起的内存泄漏 1. 配置文件使用说明 在程序中通过 #include “vld.h” 的方式检测内存…

    C++ 2023年4月18日
    00
  • C++ 入门

    001 c++ 如何工作 任何以 # 开头的语句,都是预处理语句,所谓的预处理语句,在编译之前,就已经被处理了 关键字 include:找到 <> 文件(通常称为“头文件”),然后将 <> 中的所有内容拷贝到现在的文件里 main()比较特殊,虽然它的返回值类型是 int,但它不一定需要返回值,如果不设置返回值,默认返回 0 <…

    C++ 2023年5月11日
    00
  • Qt源码阅读(四) 事件循环

    事件系统 文章为本人理解,如有理解不到位之处,烦请各位指正。 @ 目录 事件系统 什么是事件循环? 事件是如何产生的? sendEvent postEvent 事件是如何处理的? 事件循环是怎么遍历的? 事件过滤器 event 夹带私货时间 Qt的事件循环,应该是所有Qter都避不开的一个点,所以,这篇博客,咱们来了解源码中一些关于Qt中事件循环的部分。先抛…

    C++ 2023年4月18日
    00
  • day3 函数的定义和调用,练习编写简单的程序(记录1)

    一、函数的定义 可以分为以下两种: 1、函数声明和函数定义分离 这种方法将函数声明和函数定义分开,通常在头文件中先声明函数原型,然后在源文件中实现函数定义。 例如,头文件 example.h 中声明了一个函数 add: #ifndef EXAMPLE_H #define EXAMPLE_H int add(int a, int b); // 声明函数原型 #…

    C++ 2023年4月18日
    00
  • C++文件处理

    ? 新建文件 //这是要操作的文件名称 string str_filename = “E:/data/t/haha.txt”; //创建一个流对象 o 就是从这个流对象出去, 出到哪里, 当然是我们要建立的文件 ofstream ofs; //out会覆盖 ofs.open(str_filename, ios::out); ofs << “我创建…

    C++ 2023年4月17日
    00
  • 记一次 腾讯会议 的意外崩溃分析

    一:背景 1. 讲故事 前段时间在用 腾讯会议 直播的时候,居然意外崩溃了,还好不是在训练营上课,不然又得重录了,崩完之后发现 腾讯会议 的 bugreport 组件会自动生成一个 minidump,截图如下: 作为一个.NET高级调试的技术博主,非 .NET 的程序也得要研究研究哈???,有了这个好奇心,也有了这个 dump,接下来用 windbg 看一看…

    C++ 2023年4月22日
    00
  • C++重载的奥义之运算符重载

    0、引言         重载,顾名思义从字面上理解就是重复装载,打一个不恰当的比方,你可以用一个篮子装蔬菜,也可以装水果或者其它,使用的是同一个篮子,但是可以用篮子重复装载的东西不一样。         正如在之前的文章《重载的奥义之函数重载》中介绍的类似,函数的重载是指利用相同的函数名设计一系列功能相近,但是功能细节不一样的函数接口;因此运算符重载也是指…

    C++ 2023年4月18日
    00
合作推广
合作推广
分享本页
返回顶部