无法理解在C中访问二维数组的这种方式

问题描述 投票:1回答:2

我遇到了这段代码,发现很奇怪,它可以打印5。我不明白为什么将int *强制转换为基本上是一维数组的原因。有人可以解释吗?

int main()
{
    int v[2][3] = {{1,2,3},{4,5,6}};
    int* c = (int*)v;
    printf("%d\n", c[4]);
}
c arrays pointers multidimensional-array casting
2个回答
3
投票

让我们谈谈数组下标的工作原理。

[首先,请记住,数组下标操作a[i]被定义为*(a + i)-也就是说,给定地址a,从该地址偏移i个元素(不是字节!)并取消引用结果:

   +---+
a: |   |
   +---+
   |   |
   +---+
    ...
   +---+
   |   | <--- a + i
   +---+

这有两个原因:

除非它是sizeof_Alignof或一元&运算符的操作数,或者是用于在声明中初始化字符数组的字符串文字,否则expression类型为“ N” -T“的-element数组将被转换(“ decay”)为“ pointer to T”类型的表达式,该表达式的值将成为数组第一个元素的地址。如果T本身是数组类型(例如int [2][3]或“ int的3元素数组的2元素数组”),则最后将指针指向数组类型(int (*)[3] ,或“指向int的3元素数组的指针。

指针算术考虑了指向类型的大小-如果pint *并存储int对象的地址,则p + 1产生下一个int ] object,而不是下一个字节。如果p是指向intint (*)[3])的3元素数组的指针并存储数组的地址,则p + 1产生C0]的下一个3元素数组的地址。

图解:

int

[左图是具有 int int * int [3] int (*)[3] +---+ +---+ | 1 | <--- p | 1 | <--- p +---+ + - + | 2 | <--- p + 1 | 2 | +---+ + - + | 3 | | 3 | +---+ +---+ | 4 | | 4 | <--- p + 1 +---+ + - + | 5 | | 5 | +---+ + - + | 6 | | 6 | +---+ +---+ 指针的int对象的序列,而右图是具有int *指针的int [3]对象的序列。

所以发生的是,您正在获取int (*)[3]的第一个元素的地址,但是您将其视为v,而不是int *

int (*)[3]

您基本上是在右边拍摄照片,并假装是左边的照片。因此,int* c = (int*)v; 对应于序列中的第5个元素,在这种情况下为c[4]

现在,此行为是未定义-5int (*)[3]不是兼容类型,并且不能保证以此方式尝试访问int *的元素。使用哪种更安全]

v

没有强制转换可以解决不兼容的类型,并且可以获得完全相同的效果。


0
投票

该标准未明确声明可以将一组相同类型的连续对象用作数组。

尽管这样做可能会并且可以正常工作很多次,但您不能依靠它始终工作。

您可以使用指针指向数组类型int *c = &v[0][0]; // int * = int *

(*arr)[]

请注意,索引符号类似于2D数组的索引符号。

或简单地使指针指向您要访问的特定索引的地址。

int v[2][3] = {{1,2,3},{4,5,6}};
int (*c)[3] = v;
printf("%d\n", c[0][4]);
© www.soinside.com 2019 - 2024. All rights reserved.