繁体   English   中英

有人可以帮我在C中使用这些索引吗

[英]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标准:

[C11§6.5.2.1¶3]

连续的下标运算符指定多维数组对象的元素。 如果E是尺寸为ixjx 的n维数组 (n> = 2)。 xk, 然后将E(用作左值除外)转换为指向维度为jx 的(n-1)维数组的指针 如果将一元*运算符显式或隐式地应用到此指针,则结果是被引用的(n-1)维数组,如果将其用作左值,则其本身将转换为指针 由此可见,数组以行优先顺序存储(最后一个下标变化最快)。

[C11§6.5.6¶8]

将具有整数类型的表达式添加到指针或从指针中减去时,结果将具有指针操作数的类型。 如果指针操作数指向数组对象的元素,并且数组足够大,则结果指向与原始元素偏移的元素,以使结果数组元素和原始数组元素的下标之差等于整数表达式。 换句话说,如果表达式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的大小。

就内存地址而言,假设4sizeof(int) ,这意味着a + (i*sizeof(int[2])) + (j*sizeof(int)) 对于i=2j=-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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM