首页 > C/C++ > 动态二维数组的申请与释放:使用指针数组和数组指针在物理空间上的区别

动态二维数组的申请与释放:使用指针数组和数组指针在物理空间上的区别

2012年3月18日 发表评论 阅读评论
文章作者:Yx.Ac   文章来源:勇幸|Thinking (http://www.ahathinking.com)   转载请注明,谢谢合作。

---

上一篇文章中,我们提到使用数组指针申请动态二维数组时的释放问题,在C/C++中,动态申请二维数组有两种方式,一种是先申请一个指向所需类型的指针数组,然后对数组中的每个元素再依次申请空间,在物理形态上该方法申请了两次空间;另一种是使用数组指针直接申请所需的空间,物理形态上该方法只申请了一次空间。

二者在内存的物理空间上是具有不同的表现形式的,如图所示,本节我们就简单讨论下。

两种方法皆见代码,为了对比,我们也定义了一个一维数组;为了验证上面所说的二者在物理空间上的形态差别,我们分别输出了一系列变量。

#include <stdio.h>

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的区别

  • new/delete是C++中的运算符,可以重载;malloc/free则是标准库函数
  • 如果是非内置对象类型,new/delete在执行时会相应地调用构造函数和析构函数; malloc/free则不会。
  • 使用方法上的区别,如上面划横线的部分分析。

(全文完)