【问题标题】:Why the indexing affects a complete array instead of one item ? (c#)为什么索引会影响一个完整的数组而不是一个项目? (C#)
【发布时间】:2022-12-07 19:42:31
【问题描述】:

我在 C# 中遇到了一个奇怪的行为。我创建了一个 int[][] 数组,如下所示:

int[][] m_dist = Enumerable.Repeat(Enumerable.Repeat(-1, m.Length).ToArray(), m.Length).ToArray();

数组看起来像这样:

-1,-1,-1,-1,-1,-1,

-1,-1,-1,-1,-1,-1,

-1,-1,-1,-1,-1,-1,

-1,-1,-1,-1,-1,-1,

-1,-1,-1,-1,-1,-1,

-1,-1,-1,-1,-1,-1,

后来,当我试图修改单个数组元素时,我被惊呆了,因为不仅更改了一个项目,而且更改了一个完整的 int[] 数组:

 m_dist[1][1] = 0;

输出是:

-1,0,-1,-1,-1,-1,

-1,0,-1,-1,-1,-1,

-1,0,-1,-1,-1,-1,

-1,0,-1,-1,-1,-1,

-1,0,-1,-1,-1,-1,

-1,0,-1,-1,-1,-1,

我怀疑在创建数组的过程中发生了一些事情,因此我将其简化为:

 //int[][] m_dist = Enumerable.Repeat(Enumerable.Repeat(-1, m.Length).ToArray(), m.Length).ToArray();
 
 int[][] m_dist = new int[m.Length][];
 for (int i = 0; i < m_dist.Length; i++)
 {
    m_dist[i] = new int[m.Length];
    for (int j = 0; j < m_dist[i].Length; j++)
    {
       m_dist[i][j] = -1;
    }
 }

通过这种初始化,寻址是完美的。
当然我可以接受这个解决方案,但我想了解我第一次尝试时发生了什么。
如果有人可以解释那会很棒!

调试代码:

 int[][] m_dist = Enumerable.Repeat(Enumerable.Repeat(-1, m.Length).ToArray(), m.Length).ToArray();

 for (int i = 0; i < m_dist.Length; i++)
 {
    for (int j = 0; j < m_dist[i].Length; j++)
    {
       Console.Write(m_dist[i][j] + ",");
    }
    Console.Write("\n");
 }

 Console.WriteLine();

 m_dist[1][1] = 0;

 for ( int i = 0; i< m_dist.Length; i++ )
 {
    for (int j = 0; j < m_dist[i].Length; j++)
    {
       Console.Write(m_dist[i][j] + ",");
    }
    Console.Write("\n");
 }

 Console.WriteLine();

当然我可以接受这个解决方案,但我想了解我第一次尝试时发生了什么。如果有人能解释一下那就太好了!

【问题讨论】:

  • 显然是因为它多次是数组的同一个实例......你的代码基本上是int[] a = new [] {.... }......然后是int[][] aa = new [][] { a, a, a, a, a, a }
  • @Selvin 对你来说“很明显”,但对 OP 来说显然不是那么明显。 :D

标签: c# arrays multidimensional-array indexing initialization


【解决方案1】:

让我解开这一行,这样你就可以看到到底发生了什么:

int[][] m_dist = Enumerable.Repeat(Enumerable.Repeat(-1, m.Length).ToArray(), m.Length).ToArray();

展开我们得到的表达式:

int[] array = Enumerable.Repeat(-1, m.Length).ToArray();
int[][] m_dist = Enumerable.Repeat(array, m.Length).ToArray();

您创建一个填充了 -1 值的单个 array,然后创建一个数组 m_dist,其中包含重复引用该数组. m_dist 中的每个条目都指向 array,因此通过所有这些引用反映通过任何这些引用编辑元素。

您要做的是创建 m.Length 单独的数组:

int[][] m_dist = Enumerable.Range(0, m.Length)
    .Select(_ => Enumerable.Repeat(-1, m.Length).ToArray())
    .ToArray();

【讨论】:

    【解决方案2】:

    在您的第一次尝试中,问题是您正在创建对同一个内部数组的多个引用,而不是为外部数组中的每个元素创建一个新数组。这可以在以下代码行中看到:

    int[][] m_dist = Enumerable.Repeat(Enumerable.Repeat(-1, m.Length).ToArray(), m.Length).ToArray();
    

    在这里,您使用 Enumerable.Repeat() 方法创建一个新数组,其中填充值 -1,然后调用 ToArray() 方法将其转换为整数数组。然后再次调用Enumerable.Repeat(),将先前创建的数组作为参数传递,以创建一个新数组,其中填充了对原始数组的引用。最后,您再次调用 ToArray() 将其转换为二维整数数组。

    问题在于,因为内部数组只创建一次然后被多次引用,所以修改内部数组中的任何元素都会影响外部数组中对该数组的所有引用。这就是为什么当您修改m_dist[1][1] 处的元素时,整个内部数组都会被修改,而不仅仅是那个元素。

    在您的第二次尝试中,您正在为外部数组中的每个元素创建一个新的内部数组,从而避免了这个问题。这可以在以下代码中看到:

    int[][] m_dist = new int[m.Length][];
    for (int i = 0; i < m_dist.Length; i++)
    {
      m_dist[i] = new int[m.Length];
      for (int j = 0; j < m_dist[i].Length; j++)
      {
         m_dist[i][j] = -1;
      }
    }
    

    在这里,您使用 for 循环为外部数组中的每个元素创建一个新的内部数组,然后将内部数组中的每个元素初始化为 -1。因为每个内部数组都是独立创建的,所以修改一个内部数组中的元素不会影响其他内部数组,因此不会出现您在第一次尝试时遇到的问题。

    【讨论】:

      【解决方案3】:

      Enumerable.Repeat 顾名思义,它会重复您提供的内容。你给它数组,这些是引用类型,所以同一个数组是共享的。

      我会简单地使用 for 循环来初始化数组:

      int[][] m_dist = new int[m.Length][];
      for (int i = 0; i < m_dist.Length; i++)
      {
          m_dist[i] = new int[m.Length];
      }
      

      由于您想将所有 int 初始化为 -1:

      for (int i = 0; i < m_dist.Length; i++)
      {
          m_dist[i] = new int[arrayCount];
          for (int ii = 0; ii < m_dist[i].Length; ii++)
              m_dist[i][ii] = -1;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-11-24
        • 2021-02-17
        • 2020-09-29
        相关资源
        最近更新 更多