【问题标题】:What's the difference between arrays of arrays and multidimensional arrays?数组数组和多维数组有什么区别?
【发布时间】:2012-06-24 12:55:21
【问题描述】:

我在 C++ 聊天中与某人进行了语言无关的讨论,he said 数组数组和多维数组是两件事。

但据我所知,多维数组只不过是其他数组的数组,它们都具有相同的大小。他特别说

嗯,它们在 C 语言中,您可以在其中使用嵌套数组模拟多个维度 但这只是因为 C 实际上并不支持多维数组

谁能解释一下“多维数组”的典型计算机科学定义是什么以及为什么 C(或抽象定义“数组的数组”)不符合该定义?

【问题讨论】:

  • 这对于 SO 来说听起来有点抽象(因为我认为答案不会影响您面临的任何实际编程问题);它可能会更主题化,例如cs.stackexchange.
  • @OliCharlesworth 我想这里的语言设计师或抽象思想家的程序员绝对比 CS 中的要多得多。这个问题对我来说实际上听起来不像是科学,而不是听起来像编程相关的问题。似乎两者兼而有之。因此我想把它留在这里(特别是因为我个人还没有在那里注册,我们已经在这里有几个有趣的答案)。
  • 我认为这可能是这里的主题,因为这个问题的答案可以帮助两个 C 开发人员更好地交流。如果我在与同事的交流中使用了错误的术语,可能会影响我们的团队绩效。为一个有趣的问题 +1。

标签: c language-agnostic multidimensional-array


【解决方案1】:

采用 .NET 数组很好地说明了这一点:

C# 以嵌套方式定义的jagged arrays 之间存在区别:

int[][] jagged = new int[3][];

每个嵌套数组可以有不同的长度:

jagged[0] = new int[3];
jagged[1] = new int[4];

(请注意,其中一个嵌套数组根本没有初始化,即null。)

相比之下,multidimensional array 的定义如下:

int[,] multidim = new int[3, 4];

在这里,谈论嵌套数组是没有意义的,实际上尝试访问 multidim[0] 将是编译时错误 - 您需要提供所有维度来访问它,即 multidim[0, 1]

正如上面的声明所揭示的,它们的类型也不同。

此外,它们的处理方式完全不同。例如,您可以使用 int[] 类型的对象迭代上述锯齿状数组:

foreach (int[] x in jagged) …

但对多维数组的迭代是使用 int 类型的项目完成的:

foreach (int x in multidim) …

从概念上来说,锯齿状数组是 数组数组(...数组数组...无限)T,而多维数组是一个由T组成的数组,具有一组访问模式(即索引是一个元组)。

【讨论】:

  • 有趣,从没想过这种观点。
  • 这对我来说完全有意义,谢谢!但它似乎并没有映射到实际含义?因为实际上,如果您只指定一个维度的坐标,您将获得另一个维度的坐标数组。有点像部分应用函数(currying)。我猜 C 与多个数组维度的关系就像 haskell 与多参数函数的关系。
  • @Johannes 然后从间接的角度考虑(但这实际上是一个实现细节,因此答案中没有提到):锯齿状数组是指向其他数组的引用/指针的数组。多维数组是一个连续的存储块。我(在某种程度上)同意部分应用方面。 .NET 的数组非常愚蠢,因此它们不支持视图、子范围或类似的东西。因此也没有部分适用。
【解决方案2】:

我希望多维数组能够提供诸如“给我维数”或“给我某个列”或“给我某个子视图”之类的操作。 C 数组不提供这些操作。

【讨论】:

    【解决方案3】:

    来自维基百科:

    Multi-dimensional arrays

    指定元素所需的索引数称为数组类型的维度、维度或等级。 (此命名法与线性代数中的维度概念相冲突,[5] 它是元素的数量。因此,在计算上下文中,具有 5 行和 4 列的数字数组(即 20 个元素)被称为具有维度 2 , 但在数学中表示一个维度为 4×5 或 20 的矩阵。此外,“秩”的计算机科学含义与其在张量代数中的含义相似,但与矩阵秩的线性代数概念不同。)

    许多语言只支持一维数组。在这些语言中,多维数组通常由 Iliffe 向量表示,即对少一维数组的引用的一维数组。特别地,二维数组将被实现为指向其行的指针向量。因此,数组 A 的第 i 行和第 j 列中的元素将通过双索引(典型符号中的 A[i][j])访问。这种模拟多维数组的方式允许创建参差不齐或参差不齐的数组,其中每一行可能有不同的大小——或者,一般来说,每个索引的有效范围取决于所有前面索引的值。

    多维数组的这种表示在 C 和 C++ 软件中非常普遍。但是,C 和 C++ 将对声明为这样的多维数组使用线性索引公式,例如通过 int A[10][20] 或 int A[m][n],而不是传统的 int **A.[6]:p.81

    有关支持多维数组的语言示例,请参阅here

    【讨论】:

    • 这句话似乎与聊天中的断言相矛盾。它说“但是,C 和 C++ 将对声明为这样的多维数组使用线性索引公式”。
    • 好吧,我同意这似乎是一个特例,其中 C 似乎提供了一个真正的多维数组......事实上,我认为 int A[10][20] 本身也算作一种类型。不过,这仍然是一种特殊情况,因为在编译时必须知道尺寸...
    【解决方案4】:

    C 没有多维数组,但 C 有数组的数组。

    在标准中,使用了 多维数组 的措辞,但 C 多维数组实际上是数组的数组。来自 Kernighan & Ritchie:

    “在C语言中,二维数组实际上是一维数组,每个元素都是一个数组。”

    一些语言支持多维数组作为第一类类型。 《Expert C Programming》一书展示了支持数组数组和多维数组的 Ada 示例。

    【讨论】:

      【解决方案5】:

      我明白他的意思。他实际上从实现的角度来看它们是不同的,但实际上两者都是有效,可以说是多维数组。

      “数组数组”类型使用线性索引,因为它实际上是作为一维数组实现的,尽管在语言级别它是通过多个索引引用的。例如,在 C 中:

      int a[5][5];
      

      实际上与以下结构具有相同的结构:

      int a[25];
      

      编译器会翻译如下访问:

      a[i][j]
      

      到:

      a[i * jDimensionWidth + j]
      

      在上面的例子中,jDimensionWidth = 5。甚至可以像这样访问它:

      int* b = (int*) a;
      printf("%d\n",b[12] == a[2][2]); // should output 1
      

      正如他所说,“多维数组”类型是通过 Iliffe 向量实现的,其中索引不能线性化,因为地址也不是线性的,因为向量通常作为堆对象实现。这种多维数组不符合方程(对于二维数组):

      addr(a[i + 1]) = addr(a[i]) + (a[i].width * sizeof(a[i][j].datatype))
      

      由“array of array”类型实现。

      【讨论】:

        猜你喜欢
        • 2018-04-05
        • 2010-10-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多