为什么我使用此代码会出现分段错误?

时间:2010-06-06 02:53:45

标签: c

尝试在C中制作一个简单的矩形/ bin包装器。获取给定区域并找到任何给定大小矩形的位置。

关于4次递归后,我得到分段错误。

#include <stdio.h>
#include <stdlib.h>

typedef struct node_type PackNode;
struct node_type {
 int x , y;
 int width , height;
 int used;
 struct node_type *left;
 struct node_type *right;
};

typedef struct point_type PackPoint;
struct point_type {
 int x,y;
};


PackNode _clone(PackNode *node) {
 PackNode clone;
 clone.used = 0;
 clone.x = node->x;
 clone.y = node->y;
 clone.width = node->width;
 clone.height= node->height;
 clone.left = NULL;
 clone.right= NULL;
 return clone;
}
PackNode root;
int rcount;

PackPoint* recursiveFind(PackNode *node, int w, int h) {
 PackPoint rp;
 PackPoint *p = NULL;
 rcount++;
 printf ("rcount = %u\n", rcount);


 //left is not null go to left, if left didn't work try right.
 if (node->left!=NULL) {
  //move down to left branch

  p = recursiveFind(node->left, w, h);
  if (p!=NULL) {
   return p;
  } else {
   p =  recursiveFind(node->right, w, h);
   return p;
  }

 } else {
  //If used just return null and possible go to the right branch;
  if (node->used==1 || w > node->width || h > node->height) {

   return p;
  }

  //if current node is exact size and hasn't been used it return the x,y of the mid-point of the rectangle
  if (w==node->width && h == node->height) {

   node->used=1;


   rp.x = node->x+(w/2);
   rp.y = node->y+(h/2);

   p = &rp;
   return p;
  }


  //If rectangle wasn't exact fit, create branches from cloning it's parent.

  PackNode l_clone = _clone(node);
  PackNode r_clone = _clone(node);
  node->left = &l_clone;
  node->right = &r_clone;

  //adjust branches accordingly, split up the current unused areas
  if ( (node->width - w) > (node->height - h) )
  {
   node->left->width = w;
   node->right->x = node->x + w;
   node->right->width = node->width - w;

  } else {
   node->left->height = h;
   node->right->y = node->y + h;
   node->right->height = node->height - h;
  }

  p = recursiveFind(node->left, w, h);
  return p;
 }
 return p;
}





int main(void) {
 root = malloc(
 root.x=0;
 root.y=0;
 root.used=0;
 root.width=1000;
 root.height=1000;
 root.left=NULL;
 root.right=NULL;


 int i;
 PackPoint *pnt;
 int rw;
 int rh;
 for (i=0;i<10;i++) {
  rw = random()%20+1;
  rh = random()%20+1;
  pnt = recursiveFind(&root, rw, rh);
  printf("pnt.x,y: %d,%d\n",pnt->x,pnt->y);
 }



 return 0;

}

3 个答案:

答案 0 :(得分:4)

 if (node->left!=NULL) {
  //move down to left branch

  p = recursiveFind(node->left, w, h);
  if (p!=NULL) {
   return p;
  } else {
   p =  recursiveFind(node->right, w, h);

您永远不会检查node-&gt; right是否为NULL,因此下一次递归可能会取消引用NULL。

答案 1 :(得分:3)

在这种情况下,您将返回指向局部变量的指针:

  //if current node is exact size and hasn't been used it return the x,y of the mid-point of the rectangle
  if (w==node->width && h == node->height) {

   node->used=1;


   rp.x = node->x+(w/2);
   rp.y = node->y+(h/2);

   p = &rp;
   return p;
  }

这是大禁忌。函数返回后,局部变量不再有效,因此您返回的指针指向堆栈内存,该堆栈内存现在可能用于其他内容。当你开始使用它时,你就会破坏你的堆栈,你的程序将开始表现得非常不稳定。

要解决此问题,您需要执行以下操作之一:(1)让recursiveFind()按值返回PackNode,而不是指向PackNode的指针; (2)使用全局/静态PackNode实例,并返回指向该实例的指针(注意这会使recursiveFind()非线程安全);或(3)返回指向动态分配的PackNode实例的指针(例如,分配有malloc());这就要求recursiveFind()的调用者在不再需要的时候在返回的指针上调用free()

同样,这段代码也是错误的:

  //If rectangle wasn't exact fit, create branches from cloning it's parent.

  PackNode l_clone = _clone(node);
  PackNode r_clone = _clone(node);
  node->left = &l_clone;
  node->right = &r_clone;

您需要在堆上分配l_cloner_clone,而不是在堆栈上,因为一旦此函数返回,这些node指针将不再有效。我建议让_clone()按值返回指向PackNode(使用malloc()分配)而不是完整PackNode对象的指针。但是,如果你这样做,调用代码需要知道在不再需要该对象的某个稍后的点上对返回的指针调用free()

[此外,实现保留了以下划线开头的全局范围的标识符,因此您应该避免使用这些名称;您应该将_clone()重命名为clone()clonePackNode()]。

答案 2 :(得分:2)

如果不仔细查看代码,可以尝试使用Valgrind或GDB等工具来识别导致分段错误的行号/表达式。你可以从那里向后工作。

“给一个人一条鱼;你今天喂他了。教一个人钓鱼;而且你已经养了一辈子“