为什么对二维数组应用间接寻址会给出一个指针?

Why application of indirection to a two-dimensional array gives a pointer?

在阅读了该站点上的一些帖子后,我意识到 C 中的数组并不像我最初认为的那样只是一个常量指针,它本身是一种独特的类型,但在大多数情况下,数组“衰减”为一个常量指针到数组的第一个元素。由于这些新信息,我的脑海中出现了一个问题。假设我们有一个二维的A[10][10]。为什么表达式 *A 的结果是指向数组第一个元素的指针?我认为在这个表达式中,A 衰减到指向数组第一个元素的常量指针 A[0][0],然后间接寻址的应用应该给我们A[0][0]的值,但实际上它仍然给我们数组第一个元素的地址。当然,我的逻辑或我对数组或指针的理解有问题,所以我哪里错了?

提前致谢。

A decays to a constant pointer to the first element of the array A[0][0]

不,不是。为什么?

C 标准指定 *(pointer + integer) == pointer[integer],因此 *A 等同于 *(A + 0),即 A[0]A[0] 不会 给你元素 A[0][0] 只有一维数组,它将衰减到指向该数组第一行的第一个元素的指针。

*A 或 A[0] 本身是一个包含 10 个元素的数组,并且数组始终由指向其第一个元素的指针表示。然而,A[10][10](比方说一个整数数组)实际上是一个内存块,其中包含 100 个整数,第一行的 10,然后是第二行的 10,依此类推。但是如果表达式 *A 或 A[0] 将 return 一个 int 而不是指向该行的 ptr,那么就不可能使用表达式 A[0][0],对吗?

但是,因为这样的多维数组是单块内存,所以也可以将其转换为指针,然后使用这种表达式访问它:

((int *)A)[iRow * 10 + iCol];

相当于表达式:

A[iRow][iCol];

但是,如果二维数组可以这样声明的话:

int main()
{
    int A[10][10] = { 0 };
    A[9][9] = 9999;
    printf("==> %d\n", ((int *)A)[9 * 10 + 9]); //==> 9999
    return 0;
}

如果内存可能由单独的字节块组成(可能需要多次调用 malloc),就像这种表达式一样:

int * A[10]; // or
int ** A;

A的第一个元素是A[0],不是A[0][0]

这是因为A是十个东西的数组。 C 没有二维数组作为主要类型。具有多个维度的数组被派生或构造为多层数组。对于编译器,结果类型仍然只是一个数组,其元素恰好是进一步的数组。

因此,在*A中:

  • A 被转换为指向其第一个元素的指针。该指针是 &A[0],因此 *A 变为 *&A[0]
  • *&取消,所以表达式变成A[0].
  • A[0] 是一个包含十个元素的数组,因此它被转换为指向其第一个元素的指针,&A[0][0].