一 数组指针的空间释放
int (*p)[3] = new int [4][3];
// ...
delete []p; //---1
delete[](*p); //---2
在释放这个二维数组时,应该使用1和2哪种方式呢?哪种对呢?
其实两种方法都是可以的,二维数组,p 和 *p 指向的位置相同的,都是指向第一个元素的地址是 &p[0][0]对于C/C++如何检测内存泄露,就是简单的库调用,这里不赘述,详见下面代码和参考文献,不过注意,检测结果的信息输出是在调试的情况下查看输出窗口(output)的
#define _CRTDBG_MAP_ALLOC
#include
#include
#include
void main()
{
int (*p)[3] = new int [4][3];
//delete []p;
delete[](*p
_CrtDumpMemoryLeaks();//调试运行到该步,输出检测信息
}
执行如代码所示,对于两种释放方式,都没有检测出内存泄露,说明这两种方式都是正确的。
二 动态二维数组的申请和释放动态二维数组有两种形式,一种是指针数组,一种是数组指针
按照我自己的简单的理解:
指针数组,就是先申请一个指向数组的指针数组,然后再对每一个指针内部申请数组,一共有两次申请内存的过程
数组指针,就是一次性申请内存,直接获得一个二维数组的全貌
二者在内存的物理空间上是具有不同的表现形式的,如图所示,本节我们就简单讨论下。
#include
void main()
{
int * a = new int [3];
printf("一维数组:\na:\t%d\n*a:\t%d\n&a[0]:\t%d\n\n"
,a,*a,&a[0]);
// 使用指针数组
int **ptr = new int*[4];
for(int i = 0; i < 4; ++i)
{
*(ptr+i) = new int [3];
}
printf("指针数组一步步申请:\nptr:\t%d\n&ptr[0]:%d\n*ptr:\t%d\nptr[0]:\t%d\n&ptr[0][0]:%d\n\n"
,ptr,&ptr[0],*ptr,ptr[0],&ptr[0][0]);
// 使用数组指针
int (*p)[3] = new int [4][3];
printf("数组指针:\np:\t%d\n&p[0]:\t%d\n*p:\t%d\np[0]:\t%d\n&p[0][0]:%d\n\n"
,p,&p[0],*p,p[0],&p[0][0]);
// 释放内存
for(int i = 0; i < 4; ++i)
{
delete [] ptr[i]; //注意不要漏掉方括号
}
delete []ptr;
delete []p;
delete []a;
}
对于方法一:ptr==&ptr[0],二者皆是指针数组的第一个元素的地址,而*ptr与ptr[0]则是指针所指向的整型数组空间的第一个元素的地址,即&ptr[0][0]。
对于方法二:我们可以看出,所有的变量都是一样的,说明该方法在物理空间上不存在多个新开辟的内存,只是一次性地申请了row*col大小的空间。即为什么使用数组指针动态申请二维数组在释放空间时的写法有多种。
在C++中,对于两种方法,在释放空间时,delete [] p表示释放指针p所指向的对象,务必要记得写“[]”,才能表示释放的是数组中的每一个元素,如果是对象,则会调用析构函数。
在C语言中的free(p)就没有那么多“麻烦”了,无论是单个内置类型还是数组,free()函数的参数只要求传入指针即可(不过C中没有类与对象的实例与析构了),为什么会这样?这就是malloc的机制问题,malloc不关心申请的空间是什么类型,只关心开辟的字节数,这样一来free只需知道指针便能正确地释放内存。
说到这里,顺便小记一下new/delete和malloc/free的区别