是否可以使用负索引访问二维数组?
Is it possible to access two dimensional array with negative indexing?
我正在尝试访问程序中的二维数组,而且我正在尝试使用负索引(它有助于我的思维步骤)。我想使用最简洁的语法来访问数组元素,即 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]
之类的东西来访问数组元素。可能吗?
C++标准定义:
5.2.1/1 (...) unscoped enumeration or integral type. (...) The expression E1[E2] is identical (by definition) to *((E1)+(E2))
所以不需要正积分(不像数组的大小,根据 8.3.4 必须是正的)。 5.7 定义了 E1 + E2,当 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::vectors
和 std::array
都用 无符号整数 类型定义了 operator[]
。所以你的负索引实践不能轻易转换为更高级的数据结构
- 它适用于多维数组(由于数据的连续性),但它根本不适用于数组的数组,例如
int**
.
负索引可以用在数组下标中,[]
中的索引基本上是一个指针的偏移量,所以如果你写:
int array[5]={1,2,3,4,5};
int *arr=&array[2];
int val=arr[-2];
你得到 1 个。
据我了解,您要实现的是给定二维数组中的一个位置(代码中的 [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)
是一样的,p
加i
就是加i * ROW_LEN * sizeof(int)
,也就是移动位置按 i
行(向前或向后),保留列。 *(p + i)
的类型是 int[ROW_LEN]
,为了指向 int*
的指针运算而衰减,这意味着 p[i][j]
会将 j * sizeof(int)
添加到 p[i]
,即按 j
.
更改列
这有效(稍后我会更深入地解释):
int (*p)[3] = (int (*)[3])((int *)&arr + 4);
首先。表达式 (int *)&arr + 4
形成指向与 &arr[1][1]
相同位置的指针。
然而,我选择了第一种形式,以避免可能的反对意见,即 &arr[1][1]
形成一个指针,该指针不能用于访问子数组 arr[1]
的边界之外。在 C 中这是一个有效的反对意见,而在 C++ 中则不太清楚。 C++ 标准在这方面使用不同的措辞。无论如何,我通过在单个对象 arr
.
中使用偏移量来完全避免该主题
在那之后,它被转换成一个指向由 3 个整数组成的数组的指针。 (即与 &arr[0]
相同的类型)。
我认为可以使用它来访问 arr
中的任何 int
,尽管我还没有看到很多关于使用指向数组的指针的讨论它与有效 space 和无效 space 重叠。 (我要 post 关于那个的新问题...)
没有容易的方法来做到这一点。但你可以通过一些工作来做到这一点。基本上你所要做的就是获取指向数组的指针,然后将它们移动到你想要零位置的任何位置。
#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]);
}
这很恶心,我不建议在生产代码中这样做。但这是可能的。
我正在尝试访问程序中的二维数组,而且我正在尝试使用负索引(它有助于我的思维步骤)。我想使用最简洁的语法来访问数组元素,即 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]
之类的东西来访问数组元素。可能吗?
C++标准定义:
5.2.1/1 (...) unscoped enumeration or integral type. (...) The expression E1[E2] is identical (by definition) to *((E1)+(E2))
所以不需要正积分(不像数组的大小,根据 8.3.4 必须是正的)。 5.7 定义了 E1 + E2,当 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::vectors
和std::array
都用 无符号整数 类型定义了operator[]
。所以你的负索引实践不能轻易转换为更高级的数据结构- 它适用于多维数组(由于数据的连续性),但它根本不适用于数组的数组,例如
int**
.
负索引可以用在数组下标中,[]
中的索引基本上是一个指针的偏移量,所以如果你写:
int array[5]={1,2,3,4,5};
int *arr=&array[2];
int val=arr[-2];
你得到 1 个。
据我了解,您要实现的是给定二维数组中的一个位置(代码中的 [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)
是一样的,p
加i
就是加i * ROW_LEN * sizeof(int)
,也就是移动位置按 i
行(向前或向后),保留列。 *(p + i)
的类型是 int[ROW_LEN]
,为了指向 int*
的指针运算而衰减,这意味着 p[i][j]
会将 j * sizeof(int)
添加到 p[i]
,即按 j
.
这有效(稍后我会更深入地解释):
int (*p)[3] = (int (*)[3])((int *)&arr + 4);
首先。表达式 (int *)&arr + 4
形成指向与 &arr[1][1]
相同位置的指针。
然而,我选择了第一种形式,以避免可能的反对意见,即 &arr[1][1]
形成一个指针,该指针不能用于访问子数组 arr[1]
的边界之外。在 C 中这是一个有效的反对意见,而在 C++ 中则不太清楚。 C++ 标准在这方面使用不同的措辞。无论如何,我通过在单个对象 arr
.
在那之后,它被转换成一个指向由 3 个整数组成的数组的指针。 (即与 &arr[0]
相同的类型)。
我认为可以使用它来访问 arr
中的任何 int
,尽管我还没有看到很多关于使用指向数组的指针的讨论它与有效 space 和无效 space 重叠。 (我要 post 关于那个的新问题...)
没有容易的方法来做到这一点。但你可以通过一些工作来做到这一点。基本上你所要做的就是获取指向数组的指针,然后将它们移动到你想要零位置的任何位置。
#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]);
}
这很恶心,我不建议在生产代码中这样做。但这是可能的。