[英]Why am I getting a segmentation fault with this code?
尝试在C中制作一个简单的矩形/装箱机。采用给定的面积并找到任何给定尺寸的矩形的位置。
大约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;
}
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-> right是否为NULL,因此下一次递归可能会取消引用NULL。
在这种情况下,您将返回一个指向局部变量的指针:
//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
实例的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_clone
和r_clone
,因为同样,一旦此函数返回,这些node
指针将不再有效。 我建议_clone()
返回指向PackNode
的指针(与malloc()
一起分配),而不是按值返回完整的PackNode
对象。 但是,如果这样做,则调用代码需要知道在以后不再需要该对象时,在返回的指针上调用free()
。
[此外,实现中保留了以下划线开头的全局范围的标识符,因此应避免使用此类名称; 您应该将_clone()
重命名为clone()
或clonePackNode()
]。
在不仔细查看代码的情况下,您可以尝试使用诸如Valgrind或GDB之类的工具来识别导致分段错误的行号/表达式。 您可以从那里向后工作。
“给人一条鱼; 你今天已经喂饱了他 教人钓鱼; 你已经喂了他一辈子
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.