是否可以使用负索引访问二维数组?

时间:2015-03-24 20:37:48

标签: c++ multidimensional-array

我正在尝试访问程序中的二维数组,而且我正在尝试使用负数索引(它在心理步骤中帮助我)。我想使用访问数组元素v a[i][j]的最新语法。

然而,当我运行程序时,我会出现分段错误。

#include <iostream>

int main (void)
{
    int i,j;
    int arr[3][3];
    int ** p;

    for( i=0; i<3; i++)
    {
        for(j=0; j<3; j++)
        {
            arr[i][j] = i+j;
        }
    }

    p = (int **)&(arr[1][1]);

    for( i=-1; i<2; i++)
        {
            for(j=-1; j<2; j++)
            {
                std::cout << p[i][j] << std::endl;
            }
        }
    return 0;
}

我不想使用p[i*something + j]之类的东西来访问数组元素。有可能吗?

5 个答案:

答案 0 :(得分:1)

C ++标准定义:

  

5.2.1 / 1 (...)无范围枚举或整数类型。 (...)表达式E1 [E2]与*((E1)+(E2))相同(根据定义)

所以它不需要具有正积分(与根据8.3.4必须为正的阵列的大小不同)。当E1是指针而E2是正或负积分时,5.7定义E1 + E2。

所以是的,原则上它应该是有效的。示例:

 int a[4][5] = { { 11, 12, 13, 14,15 }, { 21, 22, 23, 24,25 }, { 31, 32, 33, 34,35 }, { 41, 42, 43, 44,45 } };
 typedef int (*myarr)[5];
 myarr p  = (myarr) &a[2][2];
 cout << p[0][0] << endl << p[-2][-2]<<endl; 

然而,这不是一个好习惯,因为:

  • 这可能会造成混乱,因为大多数人都希望指数是积极的
  • std::vectorsstd::array都定义了operator[] 无符号整数类型。因此,您的负索引实践无法轻松转换为更高级的数据结构
  • 它适用于多维数组(由于数据的连续性),但它并不适用于int**等数组数组。

答案 1 :(得分:1)

据我所知,你想要达到的目标是给定一个2D数组中的位置(代码中为[1][1]),你想要为该位置的邻域执行一些操作。其中一种可读的方法如下,我强烈建议:

int row = 1;
int col = 1;
for (int i = -1; i < 2; i++) {
    for (int j = -1; j < 2; j++) {
        std::cout << arr[row + i][col + j] << std::endl;
    }
}

虽然如果你真的想弄乱指针,有一种方法。您可以将&arr[1][1]视为指向长度为3的数组(arr的最后一个维度)的指针,它将允许您执行此操作:

static cont int ROW_LEN = 3; // 3 here is the last dimension of arr
typedef int (*arrRowPtr)[ROW_LEN]; 
arrRowPtr p = (arrRowPtr)&arr[1][1];

for (int i = -1; i < 2; i++) {
    for (int j = -1; j < 2; j++) {
        std::cout << p[i][j] << std::endl;
    }
}

为什么会有效:p[i]*(p + i)相同,将i添加到p意味着添加i * ROW_LEN * sizeof(int),即通过{移动位置} {1}}行(向前或向后),保留列。 i的类型为*(p + i),为指针算术的目的而衰减为int[ROW_LEN],这意味着int*会将p[i][j]添加到j * sizeof(int) ,即按p[i]更改列。

答案 2 :(得分:1)

这是有效的(我稍后会更深入地解释):

int (*p)[3] = (int (*)[3])((int *)&arr + 4);

首先。表达式(int *)&arr + 4形成指向与&arr[1][1]相同位置的指针。

但是我选择了第一种形式来避免可能的反对意见&arr[1][1]形成一个指针,该指针可能不会用于访问子数组arr[1]的边界之外。在C中,这是一个有效的异议,在C ++中它不太清楚。 C ++标准在该领域使用不​​同的措辞。无论如何,我完全通过在单个对象arr中使用偏移来避免该主题。

之后,它被转换成好像是一个指向3个int数组的指针。 (即与&arr[0]相同的类型)。

我认为可以使用它访问int内的任何arr,但我还没有看到很多关于使用指针到数组的讨论它重叠有效空间和无效空间。 (我将发布一个新问题......)

答案 3 :(得分:0)

负数索引可以在数组下标中使用,[]中的索引基本上是指针的偏移,所以如果你写:

 int array[5]={1,2,3,4,5};
 int *arr=&array[2];
 int val=arr[-2];

你得到1。

答案 4 :(得分:0)

没有 easy 方法可以做到这一点。但你可以做一些工作。基本上你所要做的就是获得指向数组的指针,然后将它们移动到你希望零位置的位置。

#include <assert.h>
#include <stdio.h>

int main(int argc, char* argv[]) {

    const int minIndex = -5;
    const int maxIndex = 5;
    const int size = maxIndex - minIndex;

    assert(minIndex < maxIndex);

    int arr[size][size];

    // initialize the values in the array
    for (int i = 0; i < size; ++i) {
        for (int j = 0; j < size; ++j) {
            arr[i][j] = size*i + j;
        }
    }

    // first get the shifted versions of the inner arrays
    int* shiftedInner[10]; 
    for (int i = 0; i < size; ++i) {
        shiftedInner[i] = arr[i] - minIndex;
    }
    // then shift the outer one 
    int** shifted = &shiftedInner[-minIndex];


    // and now you can work with it as if the
    // base array were arranged like you want it
    printf("%d", shifted[minIndex][minIndex]);
    printf("%d", shifted[-3][-4]);
}

这很糟糕,我不建议在生产代码中执行此操作。但这是有可能的。