前言

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

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

#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. PNG压缩工具-PNGGauntlet

    PNGGauntlet下载地址 对于前端来说非常实用的PNG压缩软件,支持拖拽,就是软件速度比较慢.

  2. 常见浏览器CSS hack方法总结

    ie6和ie7 #tip {*background:black; /*IE7 背景变黑色*/_background:orange; /*IE6 背景变橘色*/} IE8和IE9 :root .test ...

  3. docker常用管理命令

    本文只记录docker命令在大部分情境下的使用,如果想了解每一个选项的细节,请参考官方文档,这里只作为自己以后的备忘记录下来. 根据自己的理解,总的来说分为以下几种: 容器生命周期管理 — docke ...

  4. PMP备考笔记--1.1

    题型 200道中英文单选题 基本概念题(%10) 过程工具/技术和输入输出题ITTO (%10) 情景题(%70) 计算题(3-5道题) 图 pmp四大挑战 试卷100页,题干长,阅读量大,考试4个小 ...

  5. websockify文档

    一.官网地址 地址:https://github.com/novnc/websockify 二.开启代理 1.单台服务器 python /usr/local/websockify/websockify ...

  6. 对spring的简单了解

    对spring的简单了解 什么是spring Spring是一个开源框架,是为了解决企业应用开发的复杂性而创建的,同时Spring也是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架 特点 ...

  7. 线性链条件随机场(CRF)的原理与实现

    基本原理 损失函数 (线性链)CRF通常用于序列标注任务,对于输入序列\(x\)和标签序列\(y\),定义匹配分数: \[ s(x,y) = \sum_{i=0}^l T(y_i, y_{i+1}) ...

  8. 字段自动递增的数据库建表的SQL写法

    数据库建表的SQL写法如下: 数据库建表的SQL写法如下: create table dataC(  a int identity(1,2) primary key,  b varchar(20)) ...

  9. LeetCode 104. 二叉树的最大深度(Maximum Depth of Binary Tree)

    104. 二叉树的最大深度 104. Maximum Depth of Binary Tree 题目描述 给定一个二叉树,找出其最大深度. 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数. 说 ...

  10. LeetCode 637. 二叉树的层平均值(Average of Levels in Binary Tree)

    637. 二叉树的层平均值 637. Average of Levels in Binary Tree LeetCode637. Average of Levels in Binary Tree 题目 ...