【问题标题】:Static array returned by a function is being overwritten because of recursion由于递归,函数返回的静态数组被覆盖
【发布时间】:2020-11-18 13:07:36
【问题描述】:

我正在编写一个分段树算法,其中树的节点是数组(它应该代表索引的频率,这对我的问题实际上并不重要)。由于在查询树时需要返回一个数组,我想我必须使用一个静态变量。但这带来了一个问题:当查询由于递归而向下遍历树时,total 数组被覆盖。

int* query(int tree[][9], int i, int j, int pos, int qi, int qj){
  if(qi <= i && qj >= j){
    return tree[pos];
  }else if(qi > j || qj < i){
    static int empty[9];
    for (size_t k = 0; k < 9; k++) empty[k] = 0;
    return empty;
  }

  int mid = (i+j)/2;

  int *left  = query(tree,     i, mid, 2*pos+1, qi, qj);
  int *right = query(tree, mid+1,   j, 2*pos+2, qi, qj);

  static int total[9];

  for (size_t k = 0; k < 9; k++) {
    total[k] = left[k] + right[k];
  }

  return total;
}

【问题讨论】:

  • 我推荐的一种方法,而不是从“我认为我必须使用静态变量”开始,而是从您实际需要做的事情开始,然后从那里开始工作。话虽如此,您能否详细描述该算法应该做什么,以便我们可以完成它?照原样,我们知道当前代码不起作用,但我们并不真正知道它应该做什么,所以我们无法帮助您改正。
  • 该函数用于查询段树。那棵树的叶子是数组,连接它们的节点是它们的总和。它将从树的顶部开始并检查要查询的所需索引 i 和 j 是否完全重叠(在这种情况下,它返回该节点处的值)或没有重叠(返回零数组)。如果索引有部分重叠,则继续搜索当前检查的节点的左右节点,然后将左右数组的值相加到总数组中,然后返回。
  • 如果节点只是整数值,它会很好地工作,但由于它们是数组,我 [认为我] 必须使用静态变量或指针,这会导致数组被覆盖的问题。
  • 这是 C++,我们在 2020 年。使用 std::arraystd::vector
  • '我想我必须使用静态':好吧,停止这么想。你不能。 static 和递归不能混用。克服你的心理障碍。

标签: c++ algorithm pointers recursion segment-tree


【解决方案1】:

正如 Thomas 指出的,您可以使用 std::vector 或 std::array,但如果您真的想使用老式数组,我建议您不要将数组作为返回值而是作为参数传递(指向它的指针或更好的参考)像这样:

void query(int tree[][9], int i, int j, int pos, int qi, int qj, int (&ret)[9]])

你可以在函数内部填充数组。

也有可能返回一个指向数组的指针,但这会在内存管理方面造成混乱。

【讨论】:

    【解决方案2】:

    这是 C++,我们在 2020 年。使用 std::arraystd::vector

    auto query(std::array<std::array<int, 9>, 9> const &tree, int i, int j, int pos, int qi, int qj){
      if(qi <= i && qj >= j){
        return tree[pos];
      }else if(qi > j || qj < i){
        return std::array<int, 9>{};
      }
    
      int const mid = (i+j)/2;
    
      auto const left  = query(tree,     i, mid, 2*pos+1, qi, qj);
      auto const right = query(tree, mid+1,   j, 2*pos+2, qi, qj);
    
      std::array<int, 9> total;
    
      for (std::size_t k = 0; k < 9; k++) {
        total[k] = left[k] + right[k];
      }
    
      return total;
    }
    

    std::arrays 可以像原语一样使用。它们可以被复制、从函数返回并按值传递给函数。

    【讨论】:

    • 谢谢!我认为它解决了我的问题。但现在我有另一个问题。我使用了std::vector,但现在我无法访问leftright 的元素,否则我会得到segmentation fault (core dumped)。我不能使用[] 运算符。
    • @MarlonCendron 为什么使用向量而不是数组?听起来你对向量做错了什么。如果没有看到您的代码,几乎不可能说更多。
    • 我第一次尝试使用数组,但我也遇到了分段错误(我认为这是因为大小的原因,因为我需要一个 10⁶x9 矩阵作为树),所以我搜索了一下并更改了它为向量。我在哪里发送我的代码?我要创建一个新问题吗?
    • 我发现了问题:当索引没有重叠时,我让函数返回vector&lt;int&gt;{},我无法访问这个向量的索引。所以我用零填充向量:vector&lt;int&gt; empty; for (size_t k = 0; k &lt; NOTAS; k++) empty.push_back(0); return empty;
    • @MarlonCendron 是的,这是一个新问题。
    猜你喜欢
    • 2021-01-13
    • 2015-10-23
    • 2015-04-27
    • 1970-01-01
    • 2011-05-08
    • 1970-01-01
    • 2021-08-14
    • 2019-04-25
    • 1970-01-01
    相关资源
    最近更新 更多