有人可以帮我解决c中的这些指数

时间:2017-04-14 19:32:47

标签: c arrays

#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,但我不明白为什么? 指针是否存在多维数组,如[1]与单个维度中的*(a + 1)相同?

4 个答案:

答案 0 :(得分:2)

您的示例是官方未定义的行为。我将参考C标准:

[C11 §6.5.2.1 ¶3]

  

连续的下标运算符指定多维数组对象的元素。 如果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]

  

当向指针添加或从指针中减去具有整数类型的表达式时,结果具有指针操作数的类型。 如果指针操作数指向数组对象的元素,并且数组足够大,则结果指向与原始元素偏移的元素,使得结果元素和原始数组元素的下标的差异等于整数表达式。换句话说,如果表达式P指向数组对象的第i个元素,则表达式(P)+ N(等效地,N +(P))和(P)-N(其中N具有值n)分别指向数组对象的第i + n和第th个元素,只要它们存在即可。此外,如果表达式P指向数组对象的最后一个元素,则表达式(P)+1指向一个超过数组对象的最后一个元素,如果表达式Q指向一个超过数组对象的最后一个元素,表达式(Q)-1指向数组对象的最后一个元素。 如果指针操作数和结果都指向同一个数组对象的元素,或者指向数组对象的最后一个元素,则评估不应产生溢出;否则,行为未定义。如果结果指向数组对象的最后一个元素之后,则不应将其用作已计算的一元*运算符的操作数。

上面的重点是我的。表达式a[2][-2]在上述两段中具有很多意义。根据第一段a[2]将引用一个数组,特别是int[2]中包含的第三个a。此时,任何应用的下标运算符都需要对这个2个整数数组有效。

由于[-2]现在应用于int[2],因此生成的指针算法超出了它应用的聚合,并且根据第二段,是未定义的行为。

话虽如此,我所知道的大部分实现都是人们所期待的,而其他答案则记录了你获得这些价值的方式。

答案 1 :(得分:1)

声明为

的二维数组
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]等于13的一维数组的元素a[3]的值。

反向计算。如果你有一个一维数组的元素a [i]那么它有一个二维数组的以下对应元素

a[i / nCols][i % nCols ]

其中nCols是二维数组中的列数。

答案 2 :(得分:0)

我认为这不是未定义的行为;第6.5.2.1节中的C standard数组下标描述了如何解释数组下标。我将那里定义的段落应用于OP提出的示例:

int a[3][2];

这里a是一个3×2的整数数组;更确切地说,a是一个包含三个元素对象的数组,每个元素对象都是两个整数的数组。在表达式a[i]中,它等同于(*((a)+(i)))a首先转换为指向两个整数的初始数组的指针。然后根据i的类型调整a,其概念上需要将i乘以指针所指向的对象的大小,即两个int对象的数组。然后,表达式a[i][j]等同于(*(*((a)+(i)))+(j)),其中j在概念上乘以int的大小。

就内存地址而言,假设4sizeof(int),这意味着a + (i*sizeof(int[2])) + (j*sizeof(int));对于i=2j=-2,这意味着a + 16 - 8,即a + 2*sizeof(int)。在int a[3][2]的内存布局中,取消引用此内存地址可实现12

答案 3 :(得分:0)

您的数组如下所示:

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)