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

Is it possible to access two dimensional array with negative indexing?

本文关键字:访问 二维数组 索引 可以使 是否      更新时间:2023-10-16

我试图访问程序中的二维数组,也试图使用负索引(这对我的心理步骤有帮助)。我想对访问数组元素viza[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]的东西来访问数组元素。有可能吗?

这很有效(稍后我将更深入地解释):

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

首先。表达式CCD_ 3形成指向与CCD_ 4相同的位置的指针。

然而,我选择了第一种形式以避免可能的反对意见,即&arr[1][1]形成了一个指针,该指针可能不用于访问子阵列arr[1]的边界之外。在C中,这是一个有效的反对意见,而在C++中则不太清楚。C++标准在这方面使用了不同的措辞。在任何情况下,我都会通过在单个对象arr中使用偏移量来完全避免该主题。

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

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

据我所知,您试图实现的是,在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]视为指向长度为3arr的最后一个维度)的数组的指针,它将允许您执行以下操作:

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),即将位置移动i行(向前或向后),保留列。*(p + i)的类型为int[ROW_LEN],为了对int*进行指针运算而衰减,这意味着p[i][j]将把j * sizeof(int)添加到p[i],也就是说,按j更改列。

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; 

然而,这不是一个好的做法,因为:

  • 这可能会造成混乱,因为大多数人都认为指数是正数
  • CCD_ 28和CCD_ 29都具有用无符号积分类型定义的CCD_。因此,你的负面索引实践无法轻松转换为更高级的数据结构
  • 它适用于多维数组(由于数据的连续性),但它根本不适用于(int *)&arr + 41等数组数组

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

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

你得到1。

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

#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]);
}

这太恶心了,我不建议在生产代码中这样做。但这是可能的。