Trying to make a simple rectangle/bin packer in C. Takes a given area and finds placement for any given size rectangle.
About after 4 recursions is when I get the segmentation fault.
#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);
You never check if node->right is NULL, so the next recursion may dereference NULL.
You're returning a pointer to a local variable in this case:
//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;
}
That's a big no-no. The local variable is no longer valid after the function returns, so the pointer you're returning points to stack memory that's now potentially being used for something else. When you start doing stuff with that, you're corrupting your stack, and your program will start behaving very erratically.
To fix this, you'll need to do one of a few things: (1) have recursiveFind() return a PackNode by value, instead of a pointer to a PackNode; (2) use a global/static PackNode instance, and return a pointer to that (note that this then makes recursiveFind() non-thread-safe); or (3) return a pointer to a dynamically allocated instance of a PackNode (e.g. allocated with malloc()); this then requires that the caller of recursiveFind() call free() on the returned pointer at some later point when it's no longer needed.
Likewise, this code is also wrong:
//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;
You need to allocate l_clone and r_clone on the heap, not on the stack, because again, as soon as this function returns, those node pointers will no longer be valid. I'd recommend having _clone() return a pointer to a PackNode (allocated with malloc()) instead of a full PackNode object by value. If you do that, though, the calling code needs to know to call free() on the returned pointer at some later point when the object is no longer needed.
[Also, identifiers at global scope beginning with an underscore are reserved by the implementation, so you should avoid using such names; you should rename _clone() to something like clone() or clonePackNode()].
Without looking closely at your code, you might try using a tool such as Valgrind or GDB to identify the line number/expression causing the segmentation fault. You can work backwards from there.
“Give a man a fish; you have fed him for today. Teach a man to fish; and you have fed him for a lifetime”
Related
I have this project for college where I have to create a library that processes the options of an executable from the terminal.
I created this struct options_s :
typedef struct option_s option_t;
struct option_s {
char* keyword;
enum {
OptVoid,
OptInt,
OptString,
OptFloat
} spec;
union {
void (*opt_void)();
void (*opt_int)(int);
void (*opt_str)(const char*);
void (*opt_float)(float);
} fct;
option_t* next;
};
Each option type variable will hold a function that takes as a parameter an int, a float, a string or nothing. The keyword is the identifier of an option in the terminal and is for example "-o" and precedes the value that will be passed to the function.
This is how i initialize an option that takes and int as parameter :
option_t* c_null(option_t* l, const char* kw){
l = (option_t*) malloc (sizeof(option_t));
l->keyword = (char*) malloc (strlen(kw) + 1);
strcpy(l->keyword, kw);
l->next = NULL;
return l;
}
option_t* common(option_t* l, const char* kw){
while(l->next != NULL) l = l->next;
l->next = (option_t*) malloc (sizeof(option_t));
l->next->keyword = (char*) malloc (strlen(kw) + 1);
strcpy(l->next->keyword, kw);
l->next->next = NULL;
return l->next;
}
option_t* opt_int(option_t* l, const char* kw, void (*f)(int)){
if(l == NULL){
l = c_null(l, kw);
l->spec = OptInt;
l->fct.opt_int = f;
return l;
}else{
option_t* o = common(l, kw);
o->spec = OptInt;
o->fct.opt_int = f;
return l;
}
}
I am having problems with freeing the options. I wrote this function for that :
void opt_delete(option_t* l){
if(l->next != NULL) opt_delete(l->next);
free(l->keyword);
free(l);
}
This doesn't seem to work. Even after running an option that takes in a string through this function, doing opt->fct.opt_str("foo"); will still print "foo".
What might be the problem in my code?
The free() function doesn't clean the memory, it only deallocates the memory from the process and let the space deallocated free to be reallocated by another malloc().
This means that if you try to access to a piece of memory deallocated, you can find the last value you have written in. However this is only lucky case, because the access to an area of memory deallocated or not allocated, is an Undefined Behaviour.
This Question can help you: How do malloc() and free() work?
i have a task in class to the return an array of struck Symbol from huffman tree.
the function getSL get a huffman tree(only) and return struck of Symbol.
each spot in the array contain a char from the "leaf" of the tree and the
length of his code(how many cross section till the leaf).
my main problem was to find how i advance the cnt of the arry that it will not overright the arry.
thank you.
typedef struct HNode {
char chr;
struct HNode *left, *right;
} HNode;
typedef struct {
char chr;
int counter;
}Symbol;
this is what i did till now.
Symbol * getSL(HNode *root) {
if (root->left == NULL && root->right == NULL) {
Symbol* b = (Symbol*)malloc(100);
b->counter=0;
b->chr = root->chr;
return b;
}
Symbol* a = (Symbol*)malloc(100);
if (root->left != NULL) {
a= getSL(root->left);
a->counter++;
}
if (root->right != NULL) {
a= getSL(root->right);
a->counter++;
}
return a;
}
Apart from the malloc problem (see the comments already), you have a fundamental problem: You allocate a new struct, but then replace it with the one returned from the recursive call. So you lose the one created before (actually, memory leaking!).
Easiest variant would now be converting your Symbol to linked list nodes; then you simply could do:
Symbol* lastLeafFound; // probaly a function parameter!
if(!(root->left || root->right))
{
// leaf found:
Symbol* a = (Symbol*)malloc(sizeof(Symbol));
a->chr = root->chr;
a->counter = /* ... */;
a->next = NULL;
lastLeafFound->next = a;
// you might return a now as last leaf found, using it in the next recursive call
}
Sure, above code is incomplete, but should give you the idea...
If you cannot modify your struct, then you need to create an array and pass it on to every new recursive call (prefer not to use global variables instead):
void doGetSL
(
HNode* root,
Symbol** symbols, // your array to be used
unsigned int* count, // number of symbols contained so far
unsigned int* capacity // maximum possible symbols
)
Passing all data as pointers allows the function to modify them as needed and they are still available from outside...
Symbol* getSL(HNode* root)
{
if(!root)
return NULL;
unsigned int count = 0;
unsigned int capacity = 128;
// allocate a whole array:
Symbol* array = malloc(capacity*sizeof(Symbol));
if(array) // malloc could fail...
{
doGetSL(root, &array, &count, &capacity);
// as you cannot return the number of leaves together with
// the array itself, you will need a sentinel:
array[count].chr = 0;
// obvious enough, I'd say, alternatively you could
// set counter to 0 or -1 (or set both chr and counter)
}
return array;
}
doGetSL will now use above set up "infrastructure":
{
if(!(root->left || root->right))
{
if(*count == *capacity)
{
// no memory left -> we need a larger array!
// store in separate variables:
unsigned int c = *capacity * 2;
Symbol* s = realloc(symbols, c * sizeof(Symbol));
// now we can check, if reallocation was successful
// (on failure, s will be NULL!!!):
if(s)
{
// OK, we can use them...
*symbols = s; // <- need a pointer for (pointer to pointer)!
*capacity = c;
}
else
{
// re-allocation failed!
// -> need appropriate error handling!
}
}
(*symbols)[count].chr = root->chr;
(*symbols)[count].counter = /*...*/;
++*count;
}
else
{
if(root->left)
{
doGetSL(root->left, symbols, count, capacity);
}
if(root->right)
{
doGetSL(root->right, symbols, count, capacity);
}
}
}
One thing yet omitted: setting the counter. That would be quite easy: add another parameter to doGetSL indicating the current depth, which you increment right when entering doGetSL, you can then just assign this value when needed.
You can further improve above variant (especially readability), if you introduce a new struct:
struct SLData
{
Symbol* symbols, // your array to be used
unsigned int count, // number of symbols contained so far
unsigned int capacity // maximum possible symbols
};
and pass this one instead of the three pointers:
doGetSL(HNode*, struct SLData*, unsigned int depth);
struct SLData data =
{
.count = 0;
.capacity = 128;
.array = malloc(capacity*sizeof(Symbol));
};
if(data.array)
doGetSL(root, &data, 0); // again passed as pointer!
I try to use a new struct for a dynamic "MapNode"s array, yet the program crashes:
Unhandled exception at 0x000C191C in Astar.exe: 0xC0000005: Access violation reading location 0xCCCCCCCC.
I call the getConnectedNodesArray function, which calls the other two functions.
I know it's some kind of pointers problem.
When I used copies of the data instead of trying to point to existing data in MapNode map[][12] it worked.
Thanks.
typedef struct MapNode * MapNodePointer;
typedef struct MapNode{
int x;
int y;
int value;
int traversable;
double f;
double g;
double h;
MapNodePointer parentNode;
}MapNode;
typedef struct MapNodesArray{
MapNode* nodes;
int size;
}MapNodesArray;
void addNodeToEnd(MapNodesArray* arr, MapNode* p) {
arr->size++;
arr->nodes = realloc(arr->nodes, arr->size * sizeof(MapNode*));
(&(arr->nodes))[arr->size - 1] = p;
}
MapNodesArray* NewNodesArr() {
MapNode *first = realloc(NULL, 0 * sizeof(MapNode));
MapNodesArray temp = { first, 0 };
return &temp;
}
MapNodesArray* getConnectedNodesArray(MapNodePointer node, MapNode map[][12]) {
MapNodesArray* arr = NewNodesArr();
addNodeToEnd(&arr, &map[node->x - 1][node->y - 1]);
return arr;
}
You seem to fear indirection. Face it head-on and make sure you get exactly the amount you want:
typedef struct MapNode * MapNodePointer;
The above is a bad idea, because it hides the pointer-ness.
typedef struct MapNodesArray{
MapNode* nodes;
int size;
}MapNodesArray;
The above structure is no good for storing a dynmaic list of pointers to nodes. The nodes-member needs one more star: MapNode** nodes;
void addNodeToEnd(MapNodesArray* arr, MapNode* p) {
arr->size++;
arr->nodes = realloc(arr->nodes, arr->size * sizeof(MapNode*));
There's a better way to indicate the amount of memory you need: arr->size * sizeof *arr->nodes Always check for allocation failure. Bare-bones would be aborting the program. Insert here:
if(!arr->nodes) abort();
The compiler will rightfully complain about the next line now, just remove the address-of-operator:
(&(arr->nodes))[arr->size - 1] = p;
}
MapNodesArray* NewNodesArr() {
MapNode *first = realloc(NULL, 0 * sizeof(MapNode));
The above line could be replaced with MapNode* first = 0;
MapNodesArray temp = { first, 0 };
The above line defines an automatic variable, never return a pointer to that.
return &temp;
}
oops. Complete rewrite:
MapNodesArray* NewNodesArr() {
MapNodesArray temp* = malloc(sizeof *temp);
*temp = (MapNodesArray){ 0, 0 };
return temp;
}
Or even better:
MapNodesArray NewNodesArr() {
return (MapNodesArray){ 0, 0 };
}
Exactly how much memory do you think
MapNodesArray* NewNodesArr() {
MapNode *first = realloc(NULL, 0 * sizeof(MapNode));
MapNodesArray temp = { first, 0 };
return &temp;
}
will allocate? (hint: none at all.)
Also, you're returning a pointer to a local variable (via &temp). That thing dies with the function return.
Agree with what EOF has said, also the line
(&(arr->nodes))[arr->size - 1] = p;
in function addNodeToEnd, will be writing the address p in a memory location outside the the nodes array. This will lead to memory corruption.
to illustrate
say variable 'nodes' has a memory address 0x00000002 and you have assigned a memory location say 0x00000050 through the call to realloc. The statement above takes the offset (arr->size-1) from 0x00000002 instead of taking it from 0x00000050. This is because you are taking the address of nodes by using &. Something of the form
(arr->nodes)[arr->size - 1] = p;
will take the offset from 0x00000050 which is what you seem to be needing.
I am working on implementation of strongly connected component using Tarjan's algorithm. I am giving input as a linked list of nodes and edges. However, gcc compiler gives segmentation fault every time in the recursive function(where in the while loop I am checking for adjacent nodes of a vertex).
Any idea what's wrong in this code?
void strongconnect(int Vertex)
{
struct sc_node * Ver;
Ver = search_node(Vertex);
Ver->sc_index = ind; //accessing the index information of node
Ver->sc_lowlink = ind; // accessing the link information of node
//Ver->visited = 1;
ind++;
int w;
push(Vertex);
struct sc_node * to_link, *to_link1;
int to_lowlink,to_index;
int flowlink;
int min;
int from_index;
edge_trav = edge_head;
while(edge_trav != NULL) //accessing linked list of edges
{
if(edge_trav->from_vertex == Vertex)
{
to_link = search_node(edge_trav->to_vertex);
to_lowlink = to_link->sc_lowlink;
to_index = to_link->sc_index;
to_link1 = search_node(Vertex);
flowlink = to_link1->sc_lowlink;
from_index = to_link1->sc_index;
if(to_index == 0)
{ Vertex = to_link->sc_data;
printf("INSIDE RECURSION");
strongconnect(Vertex); // recursive loop
min = minimum(flowlink,to_lowlink);
to_link1->sc_lowlink = min;
}
else
{
min = minimum(flowlink, from_index);
to_link1->sc_lowlink = min;
} }
edge_trav = edge_trav->next;
}
Ver = search_node(Vertex);
if(Ver->sc_lowlink == Ver->sc_index)
{
do
{
w = pop();
printf("%d\t",w);
}while(w != Vertex);
}
}
I suggest you compile you program with gcc's -s and then run your program with valgrind. It's very useful memory leak checker. With it, you can figure out by yourself with is you program accessing an illegal memory position. As #Dogbert pointed, it looks you are dereferencing an NULL pointer.
I just started learning C and as a self-learning excercise, I am implementing data structures and algos in C. Right now I am working on a graph and this is the data structure representation of it.
typedef int graphElementT;
typedef struct graphCDT *graphADT;
typedef struct vertexTag
{
graphElementT element;
int visited;
struct edgeTag *edges;
struct vertexTag *next;
} vertexT;
typedef struct edgeTag
{
int weight;
vertexT *connectsTo;
struct edgeTag *next;
} edgeT;
typedef struct graphCDT
{
vertexT *vertices;
} graphCDT;
To this graph I added a addVertex function.
int addVertex(graphADT graph, graphElementT value)
{
vertexT *new = malloc(sizeof(*new));
vertexT *vert;
new->element = value;
new->visited = 0;
new->edges = NULL;
new->next = NULL;
int i = 0;
for(vert=graph->vertices; vert->next != NULL; vert=vert->next)
{
if(vert->element == value)
{
printf("already exists\n");
return 0;
}
}
vert->next = new;
//free(new);
printf("\ninserted %d\n", vert->element);
return 1;
}
This works fine except for three things.
if the newly added vertex is the same as the last vertex in the list, it fails to see it. To prevent this i changed the for loop limiting condition to vert != NULL, but that gives a seg fault.
if i try to free the temporarily allocated pointer, it resets the memory pointer by the pointer and this adds an infinite loop at the end of the vertex list. Is there no way to free the pointer without writing over the memory it points to? Or is it not really needed to free the pointer?
Also would destroying the graph mean destroying every edge and vertices? or is there a better approach?
Also if this data structure for graph is not a good one and there are better implementations, i would appreciate that being pointed out.
1
If you change the limiting condition to vert!=NULL , and if the loop ends with vert==NULL ,i.e. ,the vertex to be added isn't present , then you will be reading next statement :
vert->next = new;
That means you are accesing the NULL ,vert pointer , hence the seg fault .
Now to allow checking if the last element isn't the vertex to be added ,and also to prevent seg fault ,do this :
for(vert=graph->vertices; vert->next != NULL; vert=vert->next)
{
if(vert->element == value)
{
printf("already exists\n");
return 0;
}
}
if(vert->element == value)
{
printf("already exists\n");
return 0;
}
vert->next = new;
2
The temporary "new" pointer is the memory location allocated to the Vertex you added .IT IS NOT to be freed ,as freeing it will mean that you deleted the vertex you just added :O .
3
Yes , detroying the graph essentialy means the same .
It is always a good practice to implement linked list as a adjacency list implementation of graph .Although you can always use a c++ "2 D Vector" to implement the same .
Here's a working addVertex function that you can use.
I am keeping the original declarations as it is.
I have added a main () to which you can give command line arguments to test.
int addVertex(graphADT graph, graphElementT value)
{
vertexT *tmpvert , *vert ;
vert=graph->vertices ;
/*check to see whether we really need to create a new vertex*/
tmpvert = vert;
while(tmpvert != NULL)
{
/* U can put a debug printf here to check what's there in graph:
* printf("tmpvert->elem=%d ", tmpvert->element);
*/
vert = tmpvert;
if(tmpvert->element == value)
return 0;
tmpvert=tmpvert->next ;
}
/*If we are here , then we HAVE to allocate memory and add to our graph.*/
tmpvert = (vertexT*)malloc(sizeof(vertexT));
if ( NULL == tmpvert )
return 0; /* malloc failure */
tmpvert->element = value;
tmpvert->visited = 0;
tmpvert->edges = NULL;
tmpvert->next = NULL;
if ( NULL == vert )
graph->vertices = tmpvert; /*Notice that I dont use virt=tmpvert */
else
vert->next = tmpvert; /*putting stuff in next is fine */
return 1;
/* Dont try printing vert->element here ..vert will be NULL first time */
/*return code for success is normally 0 others are error.
*That way you can have your printfs and error code
*handling outside this function.But its ok for a test code here */
}
Now for the main () snippet for testing :
int main (int argc , char* argv[]) {
graphADT graph ;
graph =(graphADT) malloc ( sizeof(struct graphCDT) );
graph->vertices = NULL;
while ( --argc >0)
{
int value = atoi(argv[argc]);
addVertex(graph,value);
}
}