前言

在讨论多维数组动态开辟与释放之前,先说说什么是二维数组静态开辟与释放。

形如这种就是静态开辟内存,事先画好了内存大小

#include<iostream>
using namespace std; #define ROW 3
#define COL 4
int main()
{
int ar[COL][ROW] = { };
return ;
}

使用二级指针模拟二维数组

代码演示

#include<iostream>
#include<assert.h>
using namespace std; #define ROW 3
#define COL 4
int main()
{
int **p=(int**)malloc(sizeof(int*)*ROW);
assert(NULL != p);
for (int i=;i<ROW;++i)
{
p[i] = (int*)malloc(sizeof(int)*COL);
assert(NULL!=p[i]);
}
for (int i = ; i< ROW; ++i)
{
for (int j = ; j < COL; ++j)
{
p[i][j] = i + j;
}
}
for (int i = ; i< ROW; ++i)
{
for (int j = ; j < COL; ++j)
{
cout << p[i][j]<<" ";
}
cout << endl;
}
return ;
}

这段代码有个问题,内存泄漏。

泄露内存大小为4*3 + 4*4*3 = 60 Byte。我们知道,进程的用户空间内存中有一段内存是程序运行时需要的(堆、栈、共享内存区),栈内存由OS动态开辟回收,我们malloc的内存时是在堆中,需要我们手动释放,否则就会内存泄露。

free(p)这么释放内存可以吗?

不可以,这么仅仅是把3个int*释放了,后面int*指向的内存泄露。

正确释放内存,先释放int*指向的内存,在释放p指向的内存(即3个int*内存)

 #include<iostream>
#include<assert.h>
using namespace std; #define ROW 3
#define COL 4
int main()
{
int **p=(int**)malloc(sizeof(int*)*ROW);
assert(NULL != p);
for (int i=;i<ROW;++i)
{
p[i] = (int*)malloc(sizeof(int)*COL);
assert(NULL!=p[i]);
}
for (int i = ; i< ROW; ++i)
{
for (int j = ; j < COL; ++j)
{
p[i][j] = i + j;
}
}
for (int i = ; i< ROW; ++i)
{
for (int j = ; j < COL; ++j)
{
cout << p[i][j]<<" ";
}
cout << endl;
}
for (int i=;i<ROW;++i)
{
free(p[i]);
}
free(p);
return ;
}

代码封装一下,malloc版本

 #include<iostream>
#include<assert.h>
using namespace std;
#define Type int
#define ROW 3
#define COL 4 Type** _Malloc(int row,int col)
{
Type **p = (Type**)malloc(sizeof(Type*)*row);
assert(NULL != p);
for (int i = ; i<row; ++i)
{
p[i] = (Type*)malloc(sizeof(Type)*col);
assert(NULL != p[i]);
}
return p;
} void _Assign(Type **p, int row, int col)
{
for (int i = ; i< row; ++i)
{
for (int j = ; j < col; ++j)
{
p[i][j] = i + j;
}
}
} void _Print(Type **p, int row, int col)
{
for (int i = ; i< row; ++i)
{
for (int j = ; j < col; ++j)
{
cout << p[i][j] << " ";
}
cout << endl;
}
} void _Free(Type **p, int row)
{
for (int i = ; i<row; ++i)
{
free(p[i]);
}
free(p);
}
int main()
{
Type **p = _Malloc(ROW,COL);
_Assign(p,ROW,COL);
_Print(p, ROW, COL);
_Free(p, ROW);
return ;
}

new版本

 #include<iostream>
#include<assert.h>
using namespace std;
#define Type int
#define ROW 3
#define COL 4 Type** _New(int row,int col)
{
Type **p = new Type*[row];
assert(NULL != p); //C++一般不用断言,而是使用异常机制
for (int i = ; i<row; ++i)
{
p[i] = new Type[col];
assert(NULL != p[i]);
}
return p;
} void _Assign(Type **p, int row, int col)
{
for (int i = ; i< row; ++i)
{
for (int j = ; j < col; ++j)
{
p[i][j] = i + j;
}
}
} void _Print(Type **p, int row, int col)
{
for (int i = ; i< row; ++i)
{
for (int j = ; j < col; ++j)
{
cout << p[i][j] << " ";
}
cout << endl;
}
} void _Delete(Type **p, int row)
{
for (int i = ; i<row; ++i)
{
delete []p[i];
}
delete []p;
}
int main()
{
Type **p = _New(ROW,COL);
_Assign(p,ROW,COL);
_Print(p, ROW, COL);
_Delete(p, ROW);
return ;
}

C++的常用做法

在C++里面开辟二维数组,实际上没有上面那么麻烦。在看懂下面代码之前,需要向理解下面的思想。

数组的首元数是谁,指向数组首元素的指针真么写?

对于一维数组,如下图,首元素就是整型。整型数组首元素的地址就是int*。所以一维数组接收地址就是一个整型指针int*。

对于二维数组,必然涉及到行和列,他的首元素就不再是其中单独一行的某一个元数,而是整体一行,首元素的地址就是(一维数组的地址)int**。所以二位数组接收地址就是int**,也就是说需要使用int**指向首元素,因为首元素是一维数组,数组是int*类型。

二维数组代码演示

 #include<iostream>
#include<assert.h>
using namespace std;
#define Type int
#define ROW 3
#define COL 4 //定义数组指针类型
typedef Type(*Ar)[COL];
Ar _New()
{
Ar p= new Type[ROW][COL];
return p;
} void _Assign(Ar p, int row, int col)
{
for (int i = ; i< row; ++i)
{
for (int j = ; j < col; ++j)
{
p[i][j] = i + j;
}
}
} void _Print(Ar p, int row, int col)
{
for (int i = ; i< row; ++i)
{
for (int j = ; j < col; ++j)
{
cout << p[i][j] << " ";
}
cout << endl;
}
} void _Delete(Ar p)
{
delete []p;
}
int main()
{
Ar p = _New();
_Assign(p,ROW,COL);
_Print(p, ROW, COL);
_Delete(p);
return ;
}

三维数组代码演示

 #include<iostream>
#include<assert.h>
using namespace std;
#define Type int
#define ROW 3
#define COL 4
#define Z 5 //定义数组指针类型
typedef Type(*Ar)[ROW][COL];
Ar _New()
{
Ar p = new Type[Z][ROW][COL];
return p;
} void _Assign(Ar p, int row, int col, int z)
{
static int count = ;
for (int i = ; i < row; ++i)
{
for (int j = ; j < col; ++j)
{
for (int k = ; k < z; ++k)
{
p[i][j][k] = ++count;
cout.width();
cout.flags(ios::left);
cout << p[i][j][k] << " ";
}
cout << endl;
}
cout << endl;
}
} void _Print(Ar p, int row, int col, int z)
{
for (int k = ; k < z; ++k)
{
for (int i = ; i < row; ++i)
{
for (int j = ; j < col; ++j)
{
cout.width();
cout.flags(ios::left);
cout << p[i][j][k] << " ";
}
cout << endl;
}
cout << endl;
}
} void _Delete(Ar p)
{
delete[]p;
}
int main()
{
Ar p = _New();
_Assign(p, ROW, COL, Z);
_Print(p, ROW, COL, Z);
_Delete(p);
return ;
}

C++——多维数组动态开辟与释放的更多相关文章

  1. C Program进阶-二维数组动态内存开辟

    对于二维数组,我们知道可以用Type ArrayName[Row][Colume]的方式来定义,这是一种静态内存开辟的方式,程序在编译的时候就为该数组分配了空间,而且行和列大小也是指定的.这篇文章里我 ...

  2. C++二维数组动态申请内存

    好久没用C++刷题了,今天早上刷了几条题,感觉很陌生了.怪我,大二下实在太颓废了,没啥作为. 今天更新个关于c++二维数组内存申请的问题,当初作为菜鸟初学指针的时候,还是在这方面有点搞不通的.今天用到 ...

  3. C++基础:二维数组动态的申请内存和释放内存

    使用二维数组的时候,有时候事先并不知道数组的大小,因此就需要动态的申请内存.常见的申请内存的方法有两种:malloc/free 和 new/delete. 一.malloc/free (1)申请一维数 ...

  4. 2017.11.17 C++系列---用malloc动态给c++二维数组的申请与释放操作

    方法一:利用二级指针申请一个二维数组. #include<stdio.h> #include<stdlib.h> int main() { int **a; //用二级指针动态 ...

  5. C++二维数组动态内存分配

    对于二维数组和二维指针的内存的分配 这里首选说一下一维指针和一维数组的内存分配情况. 一维: 数组:形如int  a[5];这里定义了一个一维数组a,并且数组的元素个数是5,这里的a是这五个元素的整体 ...

  6. c指针与数组,传参问题,指针数组与数组指针的区别,二维数组动态内存分配

    一 数组的结构:顺序存储,看谭浩强中的图,牢记 1.数组名指代一种数据结构:数组 现在可以解释为什么第1个程序第6行的输出为10的问题,根据结论1,数组名str的内涵为一种数据结构,即一个长度为10的 ...

  7. C++ 动态多维数组的申请与释放

    今天在实验室的项目中遇到了一个问题,直接上代码: void ViBe::init(Mat img) { imgcol = img.cols; imgrow = img.rows; // 动态分配三维数 ...

  8. JavaScript中给二维数组动态添加元素的质朴方法

    var myData = new Array(); for(var i=0;i<tableDatas.length;i++){ var arr=tableDatas[i]; ...... /// ...

  9. C++中动态申请二维数组并释放方法

    C/C++中动态开辟一维.二维数组是非常常用的,以前没记住,做题时怎么也想不起来,现在好好整理一下. C++中有三种方法来动态申请多维数组 (1)C中的malloc/free (2)C++中的new/ ...

随机推荐

  1. Mathjax与LaTex公式简介

    MathJax与LaTex公式简介 (转载) PS: 原文链接写的非常好!!! 博主写这篇文章,一是为了防止原链接失效,二是在cnblogs上测试MathJax; 本文从math.stackexcha ...

  2. ACS712电流传感器应用

    1. 原理图 其中第7脚输出的是电压值,那么电压值和测量的电流什么关系?看下图,有3个量程,我用的是20A电流的,100mv电压对应1A电流 看下图,不同的温度会有影响,不过区别不大 最后计算的公式是 ...

  3. Tomcat教程(转)

    转载链接: https://www.cnblogs.com/jingmoxukong/p/8258837.html?utm_source=gold_browser_extension 简介 Tomca ...

  4. 解决ubuntu的firefox上网速度慢【转】

    在ubuntu上用firefox上网十分慢,但是在切换了chrome后发现上网速度很快,是解析域名上出现了问题,所以要为FF设置DNS缓存以提高速度.(在WIN下这个是自动设置好的,在ubuntu下需 ...

  5. windows server 2012 r2 无法安装 .net 3.5

    服务器需安装SQL 2012 ,因需安装.net3.5,没有想到2012出于安全竟然不让手动安装,对于源文件也是把控比较严,折腾了好一会儿才解决问题 有参才一下powershell等安装命令,均失败. ...

  6. Jenkins在Mac上的安装与维护

    卸载 开篇提前说下, 因为很久之前用安装包装过的, 我要先卸载: /Library/Application\ Support/Jenkins/Uninstall.command 注意:如果没有权限的话 ...

  7. 用Nacos做微服务架构里的服务注册与发现中心

    转自:https://www.jianshu.com/p/61608ff86344 Nacos 另一个非常重要的特性就是服务注册与发现,说到服务的注册与发现相信大家应该都不陌生,在微服务盛行的今天,服 ...

  8. LeetCode 589. N叉树的前序遍历(N-ary Tree Preorder Traversal)

    589. N叉树的前序遍历 589. N-ary Tree Preorder Traversal LeetCode589. N-ary Tree Preorder Traversal 题目描述 给定一 ...

  9. ABP中的本地化处理(下)

    在上篇文章中我们的重点是讲述怎样通过在Domain层通过PreInitialize()配置ILocalizationConfiguration中的Sources(IList<ILocalizat ...

  10. sublime自动格式化方法

    Sublime 工具自带代码格式化的功能,但在某些场景下格式化代码后并不是我们想要的代码格式,且是点击保存ctrl+s才触发的格式代码事件,so,为关闭点击ctrl+s格式代码,我们需要改命令 sav ...