[英]Can someone help me with these indices in c
#include <stdio.h>
int main()
{
int a[3][2]={10,11,12,13,14,15};
printf("%d %d",a[2][-2],a[2][-1]);
}
我得到的输出为12,13,但我不明白为什么? 是否存在指向像a [1]这样的多维数组的指针与一维中的*(a + 1)相同?
您的示例是官方未定义的行为。 我将参考C标准:
连续的下标运算符指定多维数组对象的元素。 如果E是尺寸为ixjx 的n维数组 (n> = 2)。 。 。 xk, 然后将E(用作左值除外)转换为指向维度为jx 的(n-1)维数组的指针 。 。 。 则 如果将一元*运算符显式或隐式地应用到此指针,则结果是被引用的(n-1)维数组,如果将其用作左值,则其本身将转换为指针 。 由此可见,数组以行优先顺序存储(最后一个下标变化最快)。
将具有整数类型的表达式添加到指针或从指针中减去时,结果将具有指针操作数的类型。 如果指针操作数指向数组对象的元素,并且数组足够大,则结果指向与原始元素偏移的元素,以使结果数组元素和原始数组元素的下标之差等于整数表达式。 换句话说,如果表达式P指向数组对象的第i个元素,则表达式(P)+ N(相当于N +(P))和(P)-N(其中N的值为n)表示分别存在于数组对象的第i + n个元素和第in个元素中。 此外,如果表达式P指向数组对象的最后一个元素,则表达式(P)+1指向数组对象的最后一个元素之后,如果表达式Q指向数组对象的最后一个元素之后,表达式(Q)-1指向数组对象的最后一个元素。 如果指针操作数和结果都指向同一数组对象的元素,或者指向数组对象的最后一个元素,则求值不会产生溢出; 否则,行为是不确定的。 如果结果指向数组对象的最后一个元素之后,则不应将其用作被评估的一元*运算符的操作数。
上面的重点是我的。 在以上两段中,表达式a[2][-2]
具有很多含义。 根据第一段, a[2]
将引用一个数组,特别是a
包含的第三int[2]
。 在这一点上,进一步应用的任何下标运算符都必须对该2个整数数组有效。
由于[-2]
现在应用于int[2]
,因此所得的指针算法超出了它所应用于的集合,并且根据第二段,它是未定义的行为。
话虽这么说,但我知道大多数实现都可以实现一个期望的功能,而另一个答案很好地证明了获得这些价值的方式。
声明为二维数组
int a[3][2] = { 10, 11, 12, 13, 14, 15 };
您可以将其解释为声明为的一维数组
int a[3 * 2] = { 10, 11, 12, 13, 14, 15 };
在二维数组的索引和一维数组的索引之间,存在以下关系
a[i][j]
对应于a[2 * i + j]
因此,元件a[2][-2]
的二维阵列对应于元件a[2 * 2 - 2]
的一维数组,它是到的a[2]
的值a[2]
等于至12
。 二维数组的元素a[2][-1]
的值对应于一维数组的元素a[2 * 2 - 1]
的值,即a[3]
等于13。
并进行反向计算。 如果您具有一维数组a [i]的元素,则它具有以下与二维数组对应的元素
a[i / nCols][i % nCols ]
其中nCols
是二维数组中的列数。
我不认为这是不确定的行为。 6.5.2.1段中的C标准数组下标描述了如何解释数组下标。 我将此处定义的段落应用于OP要求的示例:
int a[3][2];
这里a
是3×2的int数组; 更准确地说, a
是三个元素对象的数组,每个元素对象是两个int的数组。 在等于(*((a)+(i)))
的表达式a[i]
, a
首先转换为指向两个整数的初始数组的指针。 然后根据a
的类型对i
进行调整,从概念上讲,这需要将i
乘以指针指向的对象的大小,即两个int对象的数组。 然后,表达式a[i][j]
等效于(*(*((a)+(i)))+(j))
,其中j
从概念上乘以int的大小。
就内存地址而言,假设4
为sizeof(int)
,这意味着a + (i*sizeof(int[2])) + (j*sizeof(int))
; 对于i=2
和j=-2
这意味着a + 16 - 8
a + 2*sizeof(int)
,即a + 2*sizeof(int)
。 在int a[3][2]
的内存布局中,取消引用此内存地址可获得12
。
您的数组如下所示:
10 | 11
---+---
12 | 13
---+---
14 | 15
但是在内存中看起来像这样:
10
--
11
--
.
.
.
--
15
这意味着,如果要访问元素a[1][1]
(= 13),则不必访问1 + 1 = 2nd元素,因为必须跳过包含2个元素的整个第一行,因此访问1 * 2 + 1 = 3rd(10将是第0个)元素。
因此,如果您有一个数组:
int a[nRows][nCols];
访问a[i][j]
看起来像这样:
*(a + nCols * i + j) = val;
因此,在您的示例中它将是:
*(a + 2 * 2 + (-2)) = *(a + 2)
和
*(a + 2 * 2 + (-1)) = *(a + 3)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.