【问题标题】:Is a 2D Array an Array of Pointers?二维数组是指针数组吗?
【发布时间】:2026-02-26 19:20:05
【问题描述】:

如果我有:

int A[10][20];
printf("%p",A[3]);

它将打印A[3][0]的地址。

但是,我想知道这个包含指针的一维数组A[3]是否真的存在,或者它是通过某种方式计算出来的。

【问题讨论】:

  • @MarcoBonelli 问题是关于“指针数组”。没有声明。
  • @MarcoBonelli 从技术上讲,我认为,像这样声明的二维数组,没有 int 指针的 actual 数组;只是一个连续的 10x20 整数块。
  • 啊,是的,没错,A 中没有指针,只是一个连续的整数块。
  • 这里的'A'只是一个双指针。二维数组以行主要或列主要方式存储。 “A”指向数组的基地址。如果数组的维度和它存储的数据类型的大小已知,则可以计算一对索引的地址。
  • 在考虑底层内存安排的更微妙方面时,这实际上是一个非常好的问题。

标签: c arrays pointers multidimensional-array


【解决方案1】:

您定义A 的方式意味着编译器将为它分配一个连续 足够大的内存块以容纳10 x 20 ( 200) 整数;请参阅here(向下滚动到“多维数组”)。我相信您已经意识到,如果您要执行printf("%p", A);,您会看到该分配块的开头地址。

现在,当编译器看到表达式 A[3] 时,它会将它计算出的作为必要数量的“整数大小”添加到基地址(AA[0][0] 的基地址);在这种情况下,它将添加“3”(指定的索引)乘以所有其他维度的组合大小(在这种情况下,只有一个,即 20)。

因此,在您的情况下,没有 实际 指针数组;只是一个内存块,编译器可以根据您描述它的任何部分的方式来解释它。

但是,在更通用的方法中,实际上可以根据 实际 指针数组定义二维数组,如下所示:

int **A;
A = malloc(10 * sizeof(int*));
for (int n = 0; n < 10; ++n) A[n] = malloc(20 * sizeof(int));

在这种情况下,使用printf("%p",A[3]); 仍然有效,但它会给出与printf("%p",A);printf("%p",A[0]); 截然不同的偏移值。

也许还值得注意的是,尽管A 的这两个不同声明都可以通过像A[i][j] 这样的表达式来解析单个元素(但编译器会以不同的方式评估地址),但仍有这里是主要混乱的范围!例如,当将这样的数组传递给函数时:如果函数期望以第二种形式分配的数据,而您给它一个以第一种形式定义的数组(反之亦然),您将获得主要的未定义行为。

【讨论】:

  • 谢谢,我知道那个方法,这就是我困惑的原因。也许我不够聪明,无法理解您写的内容,我的意思是,编译器“理解”了什么?如果编译器“认为”他应该跳转到地址 3*20*sizeof(int)(对于 A[3]),为什么它会打印地址而不是存储的值?非常感谢,我为这个问题道歉
  • 您不能将二维数组传递给接受int** 的函数,除非您进行显式强制转换,在这种情况下您已经瞄准了自己的脚。
  • @Ruslan - 我认为你是对的。然而,最近,在 SO 上,我遇到了这样的事情:传递了一个 int a[n][m] 参数,我的编译器对此感到不满,所以我将其更改为 int*[],这导致了内爆。
  • 不知道,gcc 不接受它:coliru.stacked-crooked.com/a/d2cd75c036d14b89
  • @AlessandroF 回答您的评论:编译器无法打印int 值,因为您只提供了一个[] 索引。因此,它必须将其解释为一个指针——它可以(并且必须)按照描述计算的值。
【解决方案2】:

是的,有一种方法可以计算位置:

for A[i][j]
the position of the memory block will be

pos = A + i*(number_of_columns_in_each_row) + j

here A is the pointer to the first element of the array

【讨论】:

    【解决方案3】:

    但是,我想知道这个包含指针的一维数组A是否真的存在,或者它是以某种方式计算出来的。

    你定义数组A的方式:

    int A[10][20];
    

    不包含任何指针作为数组的元素。它只包含整数元素。

    如果你想创建一个指针数组,应该分配给 int-variables 的定义如下:

    int *A[10][20];
    

    您还可以设置一个指向数组开头的指针,即元素[0] [0] 通过使用:

    int *pointer;
    int *A[10][20];
    
    pointer = &A;
    

    您还可以通过增加指针来根据每个元素将指针稍微向前设置。

    pointer++;
    

    【讨论】:

    • 我认为您误解了 OP 的问题。我们都知道实际的数组包含整数(不是指针)。问题是,当引用一个单索引数组值时会发生什么?是否有指向每个“行”的指针列表?
    • 但是再看看 OP 的问题,这是关于 A[3] 的“指针”性质/值(一个一维数组)。
    • @Adrian 与任何指针的关系在哪里?他根本没有定义一个指针,也没有得到一个作为返回。
    • 代码printf("%p",A[3]);指的是一个指针(实际上是一个整数的一维数组被解释为一个指针)。 OP 的问题是,在这种情况下,这样的指针数组是否真的存在。
    • @Adrian 所以你的意思是他的问题是:如果指针存储在A[3] 中每个相应数组元素的内存位置,前提是实际上没有存储在相应数组元素的 int 值数组元素?