不规则二维数组(二级指针)

这是《数据结构、算法与应用 C++语言描述》一书中关于不规则二维数组的示例代码,我在原来的基础上进行了一些修改,以便说说自己对二级指针的理解。 

/// <summary>
/// 不规则数组
/// </summary>
void irregularArray() {
	int numberOfRows = 5;
	int length[5] = { 6,3,4,2,7 };

	int** irregularArray = new int* [numberOfRows];

	for (int i = 0; i < numberOfRows; i++) {
		irregularArray[i] = new int[length[i]];
	}

	cout << (int*)irregularArray[0] << endl;
	cout << (int*)irregularArray[1] << endl;
	cout << (int*)irregularArray[2] << endl;
	cout << (int*)irregularArray[3] << endl;
	cout << (int*)irregularArray[4] << endl;

	cout << "--------------------------------------------" << endl;
	//以下是我的本机输出的地址信息
	//010CE788
	//010CFC80
	//010C5038
	//010CF9E0
	//010CE1E8

	for (int i = 0; i < numberOfRows; i++)
	{
		for (int j = 0; j < length[i]; j++)
		{
			//以数组的方式进行赋值
			irregularArray[i][j] = 10 * i + j;
			//以指针的方式进行输出
			cout << *(*(irregularArray + i) + j) << " ";
		}
		cout << endl;
	}
	//赋值结束后,我查看了内存中的数据,因为格式问题,仅展示部分数据
	//0x010CE788   00   0   0   0  01   0   0   0
	//0x010CFC80   10   0   0   0  11   0   0   0
	//0x010C5038   20   0   0   0  21   0   0   0
	//0x010CF9E0   30   0   0   0  31   0   0   0
	//0x010CE1E8   40   0   0   0  41   0   0   0

 	//以下是我本机的输出信息
 	// 0 1 2 3 4 5
	//10 11 12
	//20 21 22 23
	//30 31
	//40 41 42 43 44 45 46

	//释放指针
	for (int i = 0; i < numberOfRows; i++) {
		//delete[] irregularArray[i];
		delete[] * (irregularArray + i);
	}
 	//释放完成后,我再次查看了内存中的数据,仍旧只展示了一部分
 	//0x010CE788  221 221 221 221 221 221 221 221
	//0x010CFC80  221 221 221 221 221 221 221 221
	//0x010C5038  221 221 221 221 221 221 221 221
	//0x010CF9E0  221 221 221 221 221 221 221 221
	//0x010CE1E8  221 221 221 221 221 221 221 221
	delete[] irregularArray;
} 

书中的原本的代码仅示例了数组下标操作二维数组的方式,没有对二级指针进行讨论,同时也没有对内存进行释放。当然,原书的本意也只是对不规则二维数组进行演示演示而已。 

int** irregularArray = new int* [numberOfRows]; 

这里以二级指针的形式,声明了一个二维数组。二级指针既是:指向指针的指针;二维数组既是:一维数组AA中的每个元素都存储一个一维数组。这两个解释,看起来都像在套娃。那为什么不规则二维数组要以二级指针的形式进行声明呢?

在C++中,我们可以声明一个指针,该指针指向一个一维数组。假设有pp,p1,p2,p3四个指针,pp指针指向长度是3的一维数组AA,AA存储了p1,p2,p3。p1指向一维数组A1,p2指向一维数组A2,p3指向一维数组A3。也就是说,实际上AA不存储A1,A2,A3,只是存储了指向A1,A2,A3的指针。

因此,“一维数组AA中的每个元素都存储一个一维数组(A1、A2、A3)”只是表现,实际实现则是“指向指针(p1、p2、p3)的指针(pp)”。因此使用二级指针来申明不规则二维数组。 

//这里划出了一片内存区域Area,irregularArray指向这片区域
int** irregularArray = new int* [numberOfRows];

//这里划出了numberOfRows片内存区域,分别是:m_1,m_2,...,m_numberOfRows
//irregularArray的元素存放指向m_1,m_2,...,m_numberOfRows的指针
for (int i = 0; i < numberOfRows; i++) {
	irregularArray[i] = new int[length[i]];
} 

把这几行代码放一起看看:一维数组AA(new int* [numberOfRows])里的每个元素都是一个一维数组(new int[length[i]])。但要注意到的是AA是int* [ ]类型的,AA里只能放了int * 型的指针。因此要理解irregularArray是指向指针的指针,而不是存着数组的数组。它只是最终表现成存着数组的数组,而不是真的存着数组的数组。这个确实是有点绕。

cout << (int*)irregularArray[0] << endl;
cout << (int*)irregularArray[1] << endl;
cout << (int*)irregularArray[2] << endl;
cout << (int*)irregularArray[3] << endl;
cout << (int*)irregularArray[4] << endl;

cout << "--------------------------------------------" << endl;
//以下是我的本机输出的地址信息
//010CE788
//010CFC80
//010C5038
//010CF9E0
//010CE1E8 

这段就可以很明显的看出,irregularArray里存的是地址(指针),而这些地址(指针),每个都指向一个一维数组。以下的代码,就是对这些被最终指向的一维数组进行操作。 

for (int i = 0; i < numberOfRows; i++)
{
	for (int j = 0; j < length[i]; j++)
	{
		//以数组的方式进行赋值
		irregularArray[i][j] = 10 * i + j;
		//以指针的方式进行输出
		cout << *(*(irregularArray + i) + j) << " ";
	}
	cout << endl;
}
//赋值结束后,我查看了内存中的数据,因为格式问题,仅展示部分数据
//0x010CE788   00   0   0   0  01   0   0   0
//0x010CFC80   10   0   0   0  11   0   0   0
//0x010C5038   20   0   0   0  21   0   0   0
//0x010CF9E0   30   0   0   0  31   0   0   0
//0x010CE1E8   40   0   0   0  41   0   0   0

//以下是我本机的输出信息
// 0 1 2 3 4 5
//10 11 12
//20 21 22 23
//30 31
//40 41 42 43 44 45 46

在 i 和 j 的嵌套循环中有这种关系:

1、irregularArray[ i ][ j ] 和 *( *( irregularArray + i ) + j ) 是相同意义的。

2、& irregularArray[ i ][ j ] 和 *( irregularArray + i ) + j 是相同意义的。

3、& irregularArray[ i ] 和 irregularArray + i 是相同意义的。

4、 irregularArray即可作为数组名,又可以作为指针。

当irregularArray作为指针时,它指向一维数组 (设该数组为AA) 的首地址,则 irregularArray + i   就是AA的第 i 个元素的地址(上面第3点),而 *( irregularArray + i ) 就是AA的第 i 个元素所保存的地址,这个地址就是另一个一维数组(设该数组为Ai)的首地址,因此 *( irregularArray + i ) + j 就是Ai的第j个元素的地址(上面第2点),因此 *( *( irregularArray + i ) + j ) 就是Ai的第j个元素所保存的数据(上面第1点)。 

//释放指针
for (int i = 0; i < numberOfRows; i++) {
	//delete[] irregularArray[i];
	delete[] * (irregularArray + i);
}
//释放完成后,我再次查看了内存中的数据,仍旧只展示了一部分
//0x010CE788  221 221 221 221 221 221 221 221
//0x010CFC80  221 221 221 221 221 221 221 221
//0x010C5038  221 221 221 221 221 221 221 221
//0x010CF9E0  221 221 221 221 221 221 221 221
//0x010CE1E8  221 221 221 221 221 221 221 221
delete[] irregularArray; 

由于 *( irregularArray + i ) 就是AA的 第i 个元素所保存的地址,这个地址就是另一个一维数组(设该数组为Ai)的首地址。因此delete [ ] *( irregularArray + i )就是释放了最终被指向的所有一维数组的内存空间,最后在delete [ ] irregularArray,释放了存储这些一维数组的指针的空间。

程序结束。 

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值