【问题标题】:Sorting a multidimensional array in C++ [duplicate]在C ++中对多维数组进行排序[重复]
【发布时间】:2020-04-16 11:46:44
【问题描述】:

如下代码所示,对二维数组进行排序是否安全?

int a[3][3];
for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
        cin >> a[i][j];
    }
}
sort(&a[0][0], &a[0][0] + 3 * 3); // the built-in sort function
for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
        cout << a[i][j] << ' ';
    }
    cout << '\n';
}

我们可以将这种方式推广到任何多维数组吗?

【问题讨论】:

  • 我认为这是迂腐的 UB。 a[0] 只是一个包含 3 个元素的数组...a[0][0] + 9 不属于它的数组。
  • @Jarod42 std::sort 对 [first,last) 范围内的元素进行排序。那么,这有什么问题呢?
  • 我不确定它是否是一个有效范围,因为 2 个指针属于不同的数组。标准对指针运算有特定的规则。 int [3][3] 不是 int [9],即使它们具有相同的布局。
  • 这能回答你的问题吗? Treating 2D array as 1D array
  • 重复询问是否合法,而您要求安全。甚至碰巧你们都以std::sort 为例。仅当您可以将 2D 数组视为 1D 数组时,您才能使用这样的排序,根据重复项似乎并非如此。

标签: c++ arrays sorting


【解决方案1】:

如下代码所示,对二维数组进行排序是否安全?

我对极端情况的洞察力并不好,但只要您不访问非法索引,这似乎是安全的。

分配的二维数组位置在内存中是连续的,例如a[3][3]

a[0][0]..a[0][1]..a[0][2]..a[1][0]..a[1][1]..a[1][2]..a[2][0]..a[2][1]..a[2][2]

由于 std::sort 使用 [first,last) 范围,因此将其应用于从 a[0][0]a[2][2]+1 的范围是有意义的,即:

sort(&a[0][0], &a[2][2]+1);

或从基地址而不是结束位置考虑:

sort(&a[0][0], &a[0][0]+(3*3));

给出了正确的答案,尽管乍一看它似乎是未定义的行为,因为&amp;array[0][0]+(dim1*dim2) 似乎超出了范围。但它从不访问非法索引,因为对于int 2D 数组,指针(跟随指针算术)只会从a[0][0]a[2][2],跟随整数大小的增量。到目前为止,它似乎是正确或安全的。

然而,Jarod 想要传达的内容也同样适用——我们在上下文中有两个数组,a[0][0]..a[2][2]a[0]..a[9] 不同,因为前者的类型仍然属于 int(*)[3] ,考虑到我们的数组a[3][3] 传递给std::sort

详细说明他所说的话:

(&amp;a[0][2]) + 1 传递是在数组a[0] 末尾之后的位置。 &amp;a[1][0],在同一位置属于另一个数组:

a[0][0]..a[0][1]..a[0][2] -> Array 1 
// a[0][2] + 1 -> exceeds index of the first array among the three arrays of the array which forms a[3][3]
a[1][0]..a[1][1]..a[1][2] -> Array 2
a[2][0]..a[2][1]..a[2][2] -> Array 3

如果它仍然是正确的(如果你假设的话),那么它只有在 ((&amp;a[0][2]) + 1) - &amp;a[1][0] 等于 0 时才有意义。但它被证明显示未定义的行为而不是 0,正如 Jarod 在他的演示中所证明的那样 @987654321 @,在(&amp;a[0][0] + 3)&amp;a[1][0] 之间有一个对应的例子。 (Clang 显示一个错误,可以用来证明 UB 案例的合理性)


我们可以将这种方式推广到任何多维数组吗?

是的,为什么不呢?

这是一个三维的:

#include <iostream>
#include <algorithm>

int main() 
{
  int a[2][2][2];
  for (int i = 0; i < 2; i++) 
      for (int j = 0; j < 2; j++) 
          for (int k = 0; k < 2; k++)
              std::cin >> a[i][j][k];

  std::sort(&a[0][0][0], &a[0][0][0] + 2 * 2 * 2); 

  for (int i = 0; i < 2; i++) {
      for (int j = 0; j < 2; j++) {
          for (int k = 0; k < 2; k++)
              std::cout << a[i][j][k] << " ";
          std::cout << "\n";
      }
   }
}

【讨论】:

  • 这是正确的,因为您的数组在内存中存储为a[0][0][0] a[0][0][1] a[0][1][0] ... etc.,对吧?
  • @catfour 是的,直到a[1][1][1]
  • @catfour 您是否打算通过这种方法实现某些目标,或者您是否出于好奇而要求这样做? (我认为这是一种安全的方法。)很遗憾您的问题被标记为欺骗,但如果您想使用该逻辑解决问题,我可以在这里编辑我的答案
  • 是的,我想知道这种方式是否总是安全的,因为我看到很多人使用复杂的方法来使用std::sort而不是这种方式对多维数组进行排序,而且似乎@Jarod42在 cmets 中不同意这种方式。谢谢。
  • @catfour 这看起来很安全,或者至少我想不出它会失败的情况,没有非法访问任何索引并且输出按预期工作。但是,我建议您使用其他选项,例如 std::arraystd::vector 以及相应的组合,如果您在二维中选择 std::sort。我将包含一个使用 std::array 的示例,这是一种更好的方法,至少与 C 样式数组相比。
猜你喜欢
  • 2012-07-18
  • 1970-01-01
  • 2014-08-25
  • 1970-01-01
  • 2012-04-23
  • 2019-07-05
  • 1970-01-01
相关资源
最近更新 更多