分段错误(核心转储)错误C ++递归调用

时间:2017-05-25 10:26:04

标签: c++ heap stack-overflow heap-memory

我有一个4个顶点的循环图。

每个节点都与我存储在名为nodelabel的地图中的边相关联。

我正在尝试调用printAll(int source,int depth),这将给出从源节点(Offset 0到node size)的长度深度路径。

当深度达到650时,运行正常。我给printAll(2,800)的那一刻它给出了分段错误。

我已经调试过错误来自printAllPathsUtil函数......任何人都可以指出我发生分段错误的原因。 ?

Graph g(4); // 4 nodes
g.addEdge(0, 1);
g.addEdge(0, 2);
g.addEdge(2, 0);
g.addEdge(2, 3);
g.addEdge(3, 3);

g.addLabel(0, "AAGT");
g.addLabel(1, "CCTC");
g.addLabel(2, "TTCC");
g.addLabel(3, "CTC");
map < int, string > nodelabel; // Map containing Nodelabel corresponding to every node id
void Graph::addLabel(int v, string s) {
  nodelabel[v] = s; // Add w to v’s list.
}

void Graph::printAllPaths(int source, int depth) {
  string kmerpath;
  int * path = new int[V];
  int path_index = 0; // Initialize path[] as empty

  // Call the recursive helper function to print all paths
  for (int offset = 0; offset < nodelabel[source].length(); offset++) {
    printAllPathsUtil(source, offset, depth, path, path_index, kmerpath, 1);
    path_index = 0;

  }
}

void Graph::printAllPathsUtil(int u, int offset, int d, int path[], int & path_index, string kmerpath) {
  path[path_index] = u; // store Current node in the path[]
  path_index++;

  if (d == 0) {
    //cout << kmerpath << endl;
  } else if ((nodelabel[u].length() - offset) >= d) {
    kmerpath.append(nodelabel[u].substr(offset, d));
    printAllPathsUtil(u, offset, 0, path, path_index, kmerpath);
  } else // If current vertex is not destination
  {
    // Recur for all the vertices adjacent to current vertex
    list < int > ::iterator i;
    kmerpath.append(nodelabel[u].substr(offset, (nodelabel[u].length() - offset)));
    for (i = adj[u].begin(); i != adj[u].end(); ++i) {
      printAllPathsUtil( * i, 0, (d - (nodelabel[u].length() - offset)), path, path_index, kmerpath);
    }
  }
  path_index--; // Remove current vertex from path[]

}

1 个答案:

答案 0 :(得分:1)

使用递归与循环时,有时并不总是清楚。递归通常被认为更复杂,并且经常与函数编程相关联,旨在非常线程安全。但是,如果在递归中过深,则可以快速耗尽堆栈内存。

让我们说你有一个简单的功能:

char* foo()
{
  char a[100000];
  memset(a, 0, 100000);
  return a;
}

程序知道调用它时要分配多少内存(100,000字节,加上一些指令)。

char bar()
{
  char* c = foo();
  char b = 1;
  return c[0] + b;
}

如果你从其他地方拨打foo(),那么程序知道将foo()的内存分配给bar()加上bar()的内存。

char bar()
{
  if (condition)
  {
    return foo() + bar();
  }
  else return 0;
}

但如果你使bar()递归,那么该程序并不真正知道要分配多少,因为它不知道它会走多少倍。这是一个合理的猜测,但是如果你超过了猜测所支持的深度,那么你将得到一个堆栈溢出。

解决方案是在过度深入时循环:

char bar()
{
  char* a;
  while (condition)
  {
    a += foo();
  }
  return a;
}

在这种情况下,我们失去了设计的functional方面,但我们一次只调用foo()一次,因此每次重置循环时都会再次释放内存。

我希望这种解释是有用和正确的。我知道这些功能没有多大意义,但希望能给你一个想法。