#include <stdio.h>
int main()
{
int a[3][2]={10,11,12,13,14,15};
printf("%d %d",a[2][-2],a[2][-1]);
}
I get the output as 12,13 but I don't understand why? Does a pointer exist to a multidimensional array like a[1] is same as *(a+1) in single dimension??
我得到输出为12,13,但我不明白为什么?像[1]这样的多维数组中的指针是否与单维中的*(a + 1)相同?
4 个解决方案
#1
1
A two-dimensional array declared like
一个二维数组声明为
int a[3][2] = { 10, 11, 12, 13, 14, 15 };
you can interpret as a one dimensional array declared like
你可以解释为一个声明的一维数组
int a[3 * 2] = { 10, 11, 12, 13, 14, 15 };
Between indices of the two-dimensional array and indices of the one-dimensional array there is the following relation
在二维阵列的索引和一维阵列的索引之间存在以下关系
a[i][j]
corresponds to a[2 * i + j]
a [i] [j]对应于[2 * i + j]
So the element a[2][-2]
of the two dimensional array corresponds to the element a[2 * 2 - 2]
of the one-dimensional array that is to a[2]
The value of a[2]
is equal to 12
. And the value of the element a[2][-1]
of the two-dimensional array corresponds to the value of the element a[2 * 2 - 1]
of the one-dimensional array that is to a[3]
equal to 13.
因此,二维数组的元素a [2] [ - 2]对应于a [2]的一维数组的元素a [2 * 2 - 2] a [2]的值相等并且,二维数组的元素a [2] [ - 1]的值对应于一维数组的元素a [2 * 2-1]的值,该值为[3]。 ]等于13。
And the reverse calculation. If you have an element of a one-dimensional array a[i] then it has the following corresponding element of a two-dimensional array
并反向计算。如果你有一维数组a [i]的元素,那么它具有二维数组的以下对应元素
a[i / nCols][i % nCols ]
where nCols
is the number of columns in the two-dimensional array.
其中nCols是二维数组中的列数。
#2
2
Your example is officially undefined behavior. I'll refer to the C standard:
您的示例是官方未定义的行为。我将参考C标准:
[C11§6.5.2.1¶3]
Successive subscript operators designate an element of a multidimensional array object. If E is an n-dimensional array (n >= 2) with dimensions i x j x . . . x k, then E (used as other than an lvalue) is converted to a pointer to an (n - 1)-dimensional array with dimensions j x . . . x k. If the unary * operator is applied to this pointer explicitly, or implicitly as a result of subscripting, the result is the referenced (n - 1)-dimensional array, which itself is converted into a pointer if used as other than an lvalue. It follows from this that arrays are stored in row-major order (last subscript varies fastest).
连续的下标运算符指定多维数组对象的元素。如果E是具有尺寸i x j x的n维数组(n> = 2)。 。 。 x k,则E(用作除左值之外的值)被转换为指向尺寸为j x的(n-1)维数组的指针。 。 。 x k。如果将unary *运算符显式地应用于此指针,或者作为预订的结果隐式应用,则结果是引用的(n-1)维数组,如果用作除左值之外的其他数据本身将转换为指针。由此得出,数组以行主要顺序存储(最后下标变化最快)。
[C11§6.5.6¶8]
When an expression that has integer type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the pointer operand points to an element of an array object, and the array is large enough, the result points to an element offset from the original element such that the difference of the subscripts of the resulting and original array elements equals the integer expression. In other words, if the expression P points to the i-th element of an array object, the expressions (P)+N (equivalently, N+(P)) and (P)-N (where N has the value n) point to, respectively, the i+n-th and i-n-th elements of the array object, provided they exist. Moreover, if the expression P points to the last element of an array object, the expression (P)+1 points one past the last element of the array object, and if the expression Q points one past the last element of an array object, the expression (Q)-1 points to the last element of the array object. If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined. If the result points one past the last element of the array object, it shall not be used as the operand of a unary * operator that is evaluated.
当一个具有整数类型的表达式被添加到指针或从指针中减去时,结果具有指针操作数的类型。如果指针操作数指向数组对象的元素,并且数组足够大,则结果指向与原始元素偏移的元素,使得结果元素和原始数组元素的下标的差异等于整数表达式。换句话说,如果表达式P指向数组对象的第i个元素,则表达式(P)+ N(等效地,N +(P))和(P)-N(其中N具有值n)指向分别为数组对象的第i + n个和第n个元素,只要它们存在。此外,如果表达式P指向数组对象的最后一个元素,则表达式(P)+1指向一个超过数组对象的最后一个元素,如果表达式Q指向一个超过数组对象的最后一个元素,表达式(Q)-1指向数组对象的最后一个元素。如果指针操作数和结果都指向同一个数组对象的元素,或者指向数组对象的最后一个元素,则评估不应产生溢出;否则,行为未定义。如果结果指向数组对象的最后一个元素之后,则不应将其用作已计算的一元*运算符的操作数。
The emphasis above is mine. The expression a[2][-2]
carries a lot of meaning per the above two paragraphs. According to the first paragraphs a[2]
will refer to an array, specifically the third int[2]
contained in a
. At this point, any subscript operator applied further needs to be valid in regards to this array of 2 integers.
上面的重点是我的。表达式a [2] [ - 2]在上述两段中具有很多意义。根据第一段,[2]将引用一个数组,特别是a中包含的第三个int [2]。此时,任何应用的下标运算符都需要对这个2个整数数组有效。
Since [-2]
is now applied to an int[2]
, the resulting pointer arithmetic goes outside the aggregate it's applied to, and according to the second paragraph, is undefined behavior.
由于[-2]现在应用于int [2],因此生成的指针算法超出了它应用的聚合,并且根据第二段,是未定义的行为。
Having said that, most implementations I'm aware of do the thing one may expect, and the other answers document well how it is that you got those values.
话虽如此,我所知道的大部分实现都可以做到人们可能期待的事情,而另一个答案很好地记录了你获得这些值的方式。
#3
0
I don't think that it is undefined behaviour; The C standard at paragraph 6.5.2.1 Array subscripting describes how array subscripting is interpreted. I applied the paragraph defined there to the example asked by the OP:
我不认为这是不确定的行为;第6.5.2.1节中的C标准数组下标描述了如何解释数组下标。我将那里定义的段落应用于OP提出的示例:
int a[3][2];
Here a
is a 3 × 2 array of ints; more precisely, a
is an array of three element objects, each of which is an array of two ints. In the expression a[i]
, which is equivalent to (*((a)+(i)))
, a
is first converted to a pointer to the initial array of two ints. Then i
is adjusted according to the type of a
, which conceptually entails multiplying i
by the size of the object to which the pointer points, namely an array of two int objects. Then, an expression a[i][j]
, is equivalent to (*(*((a)+(i)))+(j))
, where j
conceptually is multiplied by the size of int.
这里a是一个3×2的整数数组;更准确地说,a是一个由三个元素对象组成的数组,每个元素对象都是两个整数的数组。在表达式a [i]中,它等价于(*((a)+(i))),a首先被转换为指向两个int的初始数组的指针。然后根据a的类型调整i,其在概念上需要将i乘以指针所指向的对象的大小,即两个int对象的数组。然后,表达式a [i] [j]等价于(*(*((a)+(i)))+(j)),其中j在概念上乘以int的大小。
In terms of memory addresses, and assuming 4
as the sizeof(int)
, this means a + (i*sizeof(int[2])) + (j*sizeof(int))
; for i=2
and j=-2
this means a + 16 - 8
, i.e. a + 2*sizeof(int)
. In the memory layout of int a[3][2]
, dereferencing this memory address achieves 12
.
就内存地址而言,假设4为sizeof(int),这意味着+(i * sizeof(int [2]))+(j * sizeof(int));对于i = 2且j = -2,这意味着+ 16-8,即+ 2 * sizeof(int)。在int [3] [2]的内存布局中,解除引用此内存地址达到12。
#4
0
Your array looks like this:
你的数组看起来像这样:
10 | 11
---+---
12 | 13
---+---
14 | 15
but in the memory it looks like this:
但在内存中它看起来像这样:
10
--
11
--
.
.
.
--
15
That means that if you want to access the element a[1][1]
(= 13) you don't have to access the 1 + 1 = 2nd element because you have to skip the entire first row with 2 elements so you have to access the 1 * 2 + 1 = 3rd (10 would be the 0th) element.
这意味着如果你想访问元素a [1] [1](= 13),你不必访问1 + 1 = 2nd元素,因为你必须跳过包含2个元素的整个第一行所以你有访问1 * 2 + 1 = 3rd(10将是第0个)元素。
So if you have an array:
所以如果你有一个数组:
int a[nRows][nCols];
accessing a[i][j]
would look like this:
访问[i] [j]看起来像这样:
*(a + nCols * i + j) = val;
So in your example it would be:
所以在你的例子中它将是:
*(a + 2 * 2 + (-2)) = *(a + 2)
and
*(a + 2 * 2 + (-1)) = *(a + 3)
#1
1
A two-dimensional array declared like
一个二维数组声明为
int a[3][2] = { 10, 11, 12, 13, 14, 15 };
you can interpret as a one dimensional array declared like
你可以解释为一个声明的一维数组
int a[3 * 2] = { 10, 11, 12, 13, 14, 15 };
Between indices of the two-dimensional array and indices of the one-dimensional array there is the following relation
在二维阵列的索引和一维阵列的索引之间存在以下关系
a[i][j]
corresponds to a[2 * i + j]
a [i] [j]对应于[2 * i + j]
So the element a[2][-2]
of the two dimensional array corresponds to the element a[2 * 2 - 2]
of the one-dimensional array that is to a[2]
The value of a[2]
is equal to 12
. And the value of the element a[2][-1]
of the two-dimensional array corresponds to the value of the element a[2 * 2 - 1]
of the one-dimensional array that is to a[3]
equal to 13.
因此,二维数组的元素a [2] [ - 2]对应于a [2]的一维数组的元素a [2 * 2 - 2] a [2]的值相等并且,二维数组的元素a [2] [ - 1]的值对应于一维数组的元素a [2 * 2-1]的值,该值为[3]。 ]等于13。
And the reverse calculation. If you have an element of a one-dimensional array a[i] then it has the following corresponding element of a two-dimensional array
并反向计算。如果你有一维数组a [i]的元素,那么它具有二维数组的以下对应元素
a[i / nCols][i % nCols ]
where nCols
is the number of columns in the two-dimensional array.
其中nCols是二维数组中的列数。
#2
2
Your example is officially undefined behavior. I'll refer to the C standard:
您的示例是官方未定义的行为。我将参考C标准:
[C11§6.5.2.1¶3]
Successive subscript operators designate an element of a multidimensional array object. If E is an n-dimensional array (n >= 2) with dimensions i x j x . . . x k, then E (used as other than an lvalue) is converted to a pointer to an (n - 1)-dimensional array with dimensions j x . . . x k. If the unary * operator is applied to this pointer explicitly, or implicitly as a result of subscripting, the result is the referenced (n - 1)-dimensional array, which itself is converted into a pointer if used as other than an lvalue. It follows from this that arrays are stored in row-major order (last subscript varies fastest).
连续的下标运算符指定多维数组对象的元素。如果E是具有尺寸i x j x的n维数组(n> = 2)。 。 。 x k,则E(用作除左值之外的值)被转换为指向尺寸为j x的(n-1)维数组的指针。 。 。 x k。如果将unary *运算符显式地应用于此指针,或者作为预订的结果隐式应用,则结果是引用的(n-1)维数组,如果用作除左值之外的其他数据本身将转换为指针。由此得出,数组以行主要顺序存储(最后下标变化最快)。
[C11§6.5.6¶8]
When an expression that has integer type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the pointer operand points to an element of an array object, and the array is large enough, the result points to an element offset from the original element such that the difference of the subscripts of the resulting and original array elements equals the integer expression. In other words, if the expression P points to the i-th element of an array object, the expressions (P)+N (equivalently, N+(P)) and (P)-N (where N has the value n) point to, respectively, the i+n-th and i-n-th elements of the array object, provided they exist. Moreover, if the expression P points to the last element of an array object, the expression (P)+1 points one past the last element of the array object, and if the expression Q points one past the last element of an array object, the expression (Q)-1 points to the last element of the array object. If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined. If the result points one past the last element of the array object, it shall not be used as the operand of a unary * operator that is evaluated.
当一个具有整数类型的表达式被添加到指针或从指针中减去时,结果具有指针操作数的类型。如果指针操作数指向数组对象的元素,并且数组足够大,则结果指向与原始元素偏移的元素,使得结果元素和原始数组元素的下标的差异等于整数表达式。换句话说,如果表达式P指向数组对象的第i个元素,则表达式(P)+ N(等效地,N +(P))和(P)-N(其中N具有值n)指向分别为数组对象的第i + n个和第n个元素,只要它们存在。此外,如果表达式P指向数组对象的最后一个元素,则表达式(P)+1指向一个超过数组对象的最后一个元素,如果表达式Q指向一个超过数组对象的最后一个元素,表达式(Q)-1指向数组对象的最后一个元素。如果指针操作数和结果都指向同一个数组对象的元素,或者指向数组对象的最后一个元素,则评估不应产生溢出;否则,行为未定义。如果结果指向数组对象的最后一个元素之后,则不应将其用作已计算的一元*运算符的操作数。
The emphasis above is mine. The expression a[2][-2]
carries a lot of meaning per the above two paragraphs. According to the first paragraphs a[2]
will refer to an array, specifically the third int[2]
contained in a
. At this point, any subscript operator applied further needs to be valid in regards to this array of 2 integers.
上面的重点是我的。表达式a [2] [ - 2]在上述两段中具有很多意义。根据第一段,[2]将引用一个数组,特别是a中包含的第三个int [2]。此时,任何应用的下标运算符都需要对这个2个整数数组有效。
Since [-2]
is now applied to an int[2]
, the resulting pointer arithmetic goes outside the aggregate it's applied to, and according to the second paragraph, is undefined behavior.
由于[-2]现在应用于int [2],因此生成的指针算法超出了它应用的聚合,并且根据第二段,是未定义的行为。
Having said that, most implementations I'm aware of do the thing one may expect, and the other answers document well how it is that you got those values.
话虽如此,我所知道的大部分实现都可以做到人们可能期待的事情,而另一个答案很好地记录了你获得这些值的方式。
#3
0
I don't think that it is undefined behaviour; The C standard at paragraph 6.5.2.1 Array subscripting describes how array subscripting is interpreted. I applied the paragraph defined there to the example asked by the OP:
我不认为这是不确定的行为;第6.5.2.1节中的C标准数组下标描述了如何解释数组下标。我将那里定义的段落应用于OP提出的示例:
int a[3][2];
Here a
is a 3 × 2 array of ints; more precisely, a
is an array of three element objects, each of which is an array of two ints. In the expression a[i]
, which is equivalent to (*((a)+(i)))
, a
is first converted to a pointer to the initial array of two ints. Then i
is adjusted according to the type of a
, which conceptually entails multiplying i
by the size of the object to which the pointer points, namely an array of two int objects. Then, an expression a[i][j]
, is equivalent to (*(*((a)+(i)))+(j))
, where j
conceptually is multiplied by the size of int.
这里a是一个3×2的整数数组;更准确地说,a是一个由三个元素对象组成的数组,每个元素对象都是两个整数的数组。在表达式a [i]中,它等价于(*((a)+(i))),a首先被转换为指向两个int的初始数组的指针。然后根据a的类型调整i,其在概念上需要将i乘以指针所指向的对象的大小,即两个int对象的数组。然后,表达式a [i] [j]等价于(*(*((a)+(i)))+(j)),其中j在概念上乘以int的大小。
In terms of memory addresses, and assuming 4
as the sizeof(int)
, this means a + (i*sizeof(int[2])) + (j*sizeof(int))
; for i=2
and j=-2
this means a + 16 - 8
, i.e. a + 2*sizeof(int)
. In the memory layout of int a[3][2]
, dereferencing this memory address achieves 12
.
就内存地址而言,假设4为sizeof(int),这意味着+(i * sizeof(int [2]))+(j * sizeof(int));对于i = 2且j = -2,这意味着+ 16-8,即+ 2 * sizeof(int)。在int [3] [2]的内存布局中,解除引用此内存地址达到12。
#4
0
Your array looks like this:
你的数组看起来像这样:
10 | 11
---+---
12 | 13
---+---
14 | 15
but in the memory it looks like this:
但在内存中它看起来像这样:
10
--
11
--
.
.
.
--
15
That means that if you want to access the element a[1][1]
(= 13) you don't have to access the 1 + 1 = 2nd element because you have to skip the entire first row with 2 elements so you have to access the 1 * 2 + 1 = 3rd (10 would be the 0th) element.
这意味着如果你想访问元素a [1] [1](= 13),你不必访问1 + 1 = 2nd元素,因为你必须跳过包含2个元素的整个第一行所以你有访问1 * 2 + 1 = 3rd(10将是第0个)元素。
So if you have an array:
所以如果你有一个数组:
int a[nRows][nCols];
accessing a[i][j]
would look like this:
访问[i] [j]看起来像这样:
*(a + nCols * i + j) = val;
So in your example it would be:
所以在你的例子中它将是:
*(a + 2 * 2 + (-2)) = *(a + 2)
and
*(a + 2 * 2 + (-1)) = *(a + 3)