首页 > 解决方案 > 为什么我可以从 int**(作为二维数组)转换为 int*?

问题描述

我写了代码 -

int arr2d[2][2] = {{1, 2}, {3, 4}};
int * arr = (int*)arr2d;
int i = 0;
for(i = 0; i < 4; i++)
{
    printf("%d  ", arr[i]);
}

输出就好像我在 arr2d 中打印了数组中的每个元素,没有什么不寻常的。为什么呢?

标签: carrayspointers

解决方案


为什么我可以从 int**(作为二维数组)转换为 int*?

你有一个误解。 数组不是指针。在大多数情况下,它们确实会衰减为指针,但这是评估问题,而不是自然问题。因此,二维数组是数组的数组,而不是指针的数组。因此,它们不会衰减为指向指针的指针,而是指向数组的指针。您的代码中没有int**任何地方涉及。

鉴于此声明:

int arr2d[2][2] = {{1, 2}, {3, 4}};

您可以在没有强制转换的情况下执行的相关指针分配是

int (*arr2d_ptr)[2];

arr2d_ptr = arr2d;  // arr2d is not a pointer, but it does decay to one in this expression

arr2d_ptr是一个指向 的二元素数组的指针int。赋值使它指向 的第一个元素arr2d。如果将其转换为 type int *,则结果指向int数组中的第一个arr2d_ptr指向的对象。例如,

int *ip = (int *) arr2d_ptr;

这很自然,因为这int正是数组的第一部分。您可以通过索引作为ip[0]或访问它*ip。您可以int将该数组中的第二个访问为ip[1].

我想问题的另一个方面是关于表达式ip[2]ip[3]. 数组是元素的连续序列。数组的数组在这方面并不特殊:它们是(较小的)数组的连续序列。因此,您的布局arr2d是这样的:

array..|array..|

. 如果你覆盖每个成员数组的布局,那么你会得到:

int|int|int|int|

,这与四个 的一维数组的布局完全相同int。这就是为什么您可以int通过索引ip(或arr在您的示例代码中)访问所有四个 s。

有趣的事实:因为数组类型的表达式衰减为指针,所以这里不需要强制转换。您可以改为取消引用 arr2d_ptr以形成一个表达式,指定 2D 数组的第一个元素,这是一个 1D 数组,并让它衰减到一个指针:

int *ip2 = *arr2d_ptr;

或者,等效地,

int *ip3 = *arr2d;

推荐阅读