是的你可以!
我不认为你可以用数组来做到这一点,但你可以用指向数组元素的指针来做到这一点。
但是,除非我有很好的理由,否则我不会这样做。负可索引指针不会是阅读您的代码的人所期望的,因此很容易意外误用。为清楚起见,使用基于函数的解决方案可能会更好 - 除非它需要非常快。
有了这个,让我们开始吧!
从您的尝试来看,您似乎对数组和指针感到困惑。请记住,它们不是一回事。
现在,C 不会阻止您使用负索引,这在您使用指针时是有意义的。所以,你可以这样做:
int a[5];
int *b = a + 2; // or &a[2]
b[-2] // is a[0]
b[-1] // is a[1]
b[0] // ia a[2], etc
所以,我认为下面的代码对你有用。
#define GRIDSIZE 101
.....
int map_memory[GRIDSIZE][GRIDSIZE];
int *map_rows[GRIDSIZE];
int **map;
int i;
int gridMidPoint = GRIDSIZE / 2;
for(i = 0; i < GRIDSIZE; i++) {
map_rows[i] = &(map_memory[i][0]) + gridMidPoint;
}
map = map_rows + gridMidPoint;
然后您可以完全按照您的预期使用它 - 网格大小为 101:
for(i = -50; i <= 50; i++) {
for(j = -50; j <= 50; j++) {
map[i][j] = i+j;
}
}
或者,更一般地说:
for(i = -1 * gridMidPoint; i <= gridMidPoint; i++) {
for(j = -1 * gridMidPoint; j <= gridMidPoint; j++) {
map[i][j] = i+j;
}
}
由于两个数组都是在堆栈上创建的,因此无需释放任何东西。
这里发生了什么事?让我分解一下。首先,我们创建后备数组:
int map_memory[GRIDSIZE][GRIDSIZE];
接下来,我们想要一个将用作行的指针数组:
int *map_rows[GRIDSIZE];
我们需要这些指针,因为它们将指向我们刚刚创建的二维数组中的数组中间。
int gridMidPoint = GRIDSIZE / 2;
这里我们计算中点。我假设您希望零的每一侧都有相同数量的数组元素 - 所以您不需要示例中的 +1。
for(i = 0; i < GRIDSIZE; i++) {
map_rows[i] = &(map_memory[i][0]) + gridMidPoint;
}
此代码遍历我们的 rows 数组中的每个元素,并将该行设置为指向二维数组中相关行的中间。你也可以写:
map_rows[i] = &map_memory[i][gridMidPoint];
但我个人认为带有多余括号和添加的版本更易于阅读。我认为如果您使用指针做不寻常的事情,您应该准确说明下一个阅读您的代码的人发生了什么。
最后,我们需要我们的map
指针指向行的中间:
map = map_rows + gridMidPoint;
我们完成了!
请记住,二维数组实际上是一块连续的内存。这意味着它map[0][gridMidPoint+1]
与 的位置相同map[1][-1*gridMidPoint]
。这实际上与普通的二维数组没有什么不同,但在调试时需要注意这一点。