如果我有一个这样的数组:
int map[21][28] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 2, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
如何创建一个更小的数组由数组内的值组成…?
像这样:
int zoomedMap[7][7] =
{
2, 2, 1, 1, 1, 1, 1,
1, 0, 0, 0, 0, 0, 1,
1, 0, 0, 0, 0, 0, 1,
1, 0, 0, 0, 0, 0, 1,
1, 0, 0, 0, 0, 0, 1,
1, 0, 0, 0, 0, 0, 1,
1, 1, 1, 1, 1, 1, 1
};
我不知道这是否有帮助,但是:
- 我知道两个数组的确切尺寸
- 我希望它可以移动较小的数组位置,最好只是通过改变X/Y值
很明显,子数组实际上只不过是主数组中的一个数据"块"(带有一些有趣的分区)。假设你正在检查边界并且不允许越界条件发生,你可以使用指针数学和一些关于主数组的基本信息来模拟子数组。
- 块总是
- 块有固定的宽度,这样
column+width
不超过你的主数组宽度。我们需要这个宽度。 - 块有固定的高度,这样
row+height
不会超过你的主数组的高度。我们需要这个高度。 - 我希望很明显,我们需要的基址是主数组(在你的情况下
map
)。
[0][0]
位置的[row][column]
偏移量,所以我们需要这些值(行和列)。这可能是最好的例子来说明。以下不是一些最终的解决方案。它甚至可能无法满足你未来需求的十分之一。相反,它旨在为您提供一个想法,告诉您如何仅使用一个指针、一些偏移量、一些大小和一些算术来实现这一目标。没有任何可以阻止您超越可能有害的限制(就像普通数组一样),所以要小心。
// internal rerefential to a submatrix in a larger fixed matrix.
template<typename T>
class Sub2D
{
public:
template<size_t R, size_t C>
Sub2D(T(&ar)[R][C], int top, int left, int height, int width)
: parent(ar[0])
, row(top)
, col(left)
, max_row(R)
, max_col(C)
{
if ((row+width) >= R || (col+height) >= C)
throw std::out_of_range("");
}
// retrieve our subrow offset into the main 2D array
T* operator [](size_t n)
{
// enable at your desire, but as Alex pointed out, all
// the standard containers let you shoot yourself in the
// foot with this operator. why not this one too =P
//if (row+n >= max_row)
// throw std::out_of_range("");
return parent + ((row+n)*max_col + col);
}
private:
T* parent;
size_t row, col;
size_t max_row, max_col;
};
像这样使用,假设你的问题中的数组是我们基于的数组:
int main()
{
// take the submatrix & [6][7] that is 7x7 in dimension.
Sub2D<int> sub(map, 6,7, 7,7);
for (size_t i=0;i<7;++i)
{
for (size_t j=0;j<7;++j)
cout << sub[i][j] << ' ';
cout << endl;
}
cout << endl;
// update an element at location [1][1] of our sub-matrix.
sub[1][1] = 9;
// reprint the *entire* main array. it better have updated.
for (size_t i=0;i<sizeof(map)/sizeof(map[0]);++i)
{
for (size_t j=0;j<sizeof(map[0])/sizeof(map[0][0]);++j)
cout << map[i][j] << ' ';
cout << endl;
}
cout << endl;
return 0;
}
产生如下输出:
2 2 1 1 1 1 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 1 1 1 1 1 1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 2 2 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 9 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
请注意,9现在就在我们期望它的位置。
显然还有很多你可以添加到这样的模板类,包括更好的范围检查,移动你的指针,快照到其他内存缓冲区等,但重点是基本的get-me-this子矩阵一个指针和一些偏移是很难打败的,特别是对于性能。
可以静态地使用循环:
const int pos_x = 6, pos_y = 7, size_x = 7, size_y = 7;
int newMap[size_x][size_y] = {0};
for( int i = pos_x; i != pos_x+size_x; ++i ) {
for( int j = pos_y; j != pos_y+size_y; ++j) {
newMap[i-pos_x][j-pos_y] = map[i][j];
}
}
虽然这不是很安全,而且很难动态地工作。你可能想用你想要的函数写一个矩阵包装器类;或者找到一个已经存在并扩展它(我会开始寻找STL或Boost的现有矩阵类)
读取Boost的uBLAS模块。它提供了Matrix和MatrixRange类,这正是您正在寻找的。
本质上,zoomedMap
应该只是一个指向更大矩阵的智能指针,它知道如何解引用并得到正确的结果。
根据您的需求,这可能就足够了:
int (*zoomedMap)[28] = reinterpret_cast<int (*)[28]>(&map[X][Y]);
这给了你一个标识符,你可以像使用一个二维数组一样使用它:zoomedMap[i][j]
。您可以通过为其分配新地址来轻松地将缩放后的地图移动到更大的数组中。
这取决于你的c++实现是否允许将float类型的指针转换为float类型数组的指针,前提是所有引用都保持在原始数组中。这很常见。
它使zoomedMap
指向与map
相同的内存。因此,你不能只改变其中一个而不改变另一个。如果你想这样做,你需要做一个副本。