Gilfoyle
Gilfoyle

Reputation: 3616

Copy members of a struct

I have a struct Node and Box given by

typedef struct Node{
    Particle p;
    Box box;
    struct Node *son[4];
}Node

and

typedef struct Box{
    double low[3];
    double up[3];
}Box

I have two functions insert() and sonumb() where I want to use these structures.

    void insert(Particle *p, Node *t){
        Box sonbox;
        int b=sonumb(&t->box, &sonbox, p);
        t->son[b]->box = sonbox; // <--- Produces Segmentation fault (core dumped)
    }

int sonumb(Box *box, Box *sonbox, Particle *p){ 
        int b=0;
        for(int d=0;d<3;d++){
            sonbox->up[d] = 0.5*box->up[d];
            sonbox->low[d] = 0.5*box->low[d];
            }
            b=1; // b=[0,3] just for this example
    }

sonum() returns an integer value b. sonbox represents after the call of sonumb() a smaller box inside of t->box. I return the right values for sonbox after the call. So sonbox is not empty. But if I want to copy those values like t->son[b]->box = sonbox I get an segmentatioin fault. What did I miss?

Upvotes: 0

Views: 74

Answers (2)

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726479

You have nearly certainly missed the allocation of son elements. In order for the expression t->son[b]->box to produce a valid target of an assignment, t->son[b] needs to be assigned a pointer to a valid Node structure. The pointer needs to point to some Node that you have previously allocated.

If child nodes are shared among nodes, this should be a malloc-ed node. This adds quite a bit of complexity, because deleting shared nodes is non-trivial. Two common approaches to working with shared nodes are to (1) allocate all nodes at once in a large array, and use them one-by-one as they become needed, and (2) add reference count to the struct, increment it when taking a pointer, and decrement it when the reference is no longer needed. The second approach is extremely difficult to implement; see if you can avoid it before committing to it.

On the other hand, if child nodes are owned exclusively by their parent, you have a very simple solution: allocate Node with malloc before the assignment of son[b] elements, and free them when you are done with the node:

Box sonbox;
int b=sonumb(&t->box, &sonbox, p);
t->son[b] = calloc(1, sizeof(Node)); // Allocate the node
t->son[b]->box = sonbox;

Use of calloc ensures that the memory of the Node is cleared prior to making other assignments. If this is not necessary, because you assign all members in the rest of your function, replace the call with malloc:

t->son[b] = malloc(sizeof(Node));

Upvotes: 1

Milind Deore
Milind Deore

Reputation: 3063

adding to @dasblinkenlight's comment.

Box sonbox;  ---> This variable is on stack 
int b=sonumb(&t->box, &sonbox, p); --> content of t->box is COPIED to sonbox, not by reference but by value. 
t->son[b]->box = sonbox; // --> Assigning stack variable is incorrect, because it will vanish once you exit function. OR as @dasblinkenlight suggested pass the value but not the pointer. 

Upvotes: 0

Related Questions