I have a struct containing dynamic struct arrays:
struct C_Node {
int id;
int num_children;
int* children;
};
struct C_Transition {
int id;
int duration;
int num_parents;
int num_children;
int* parents;
int* children;
};
struct C_PetriNet {
int num_nodes;
int num_transitions;
C_Node* nodes;
C_Transition* transitions;
};
I want to initialize and return the outer struct like the following:
C_PetriNet* Cpp_C_interface::convert_PetriNet(PetriNet petriNet) {
int num_nodes = static_cast<int>(petriNet.nodes.size());
int num_transitions = static_cast<int>(petriNet.transitions.size());
C_PetriNet* c_petriNet = (C_PetriNet*)malloc(sizeof(C_PetriNet));
C_Node* c_nodes = new C_Node[num_nodes];
C_Transition* c_transitions = new C_Transition[num_transitions];
for (int i = 0; i < num_nodes; i++) {
c_nodes[i].id = petriNet.nodes[i].id;
c_nodes[i].num_children = petriNet.nodes[i].childs.size();
c_nodes[i].children = petriNet.nodes[i].childs.data();
}
for (int i = 0; i < num_transitions; i++) {
c_transitions[i].id = petriNet.transitions[i].id;
c_transitions[i].duration = petriNet.transitions[i].duration;
c_transitions[i].num_parents = petriNet.transitions[i].parents.size();
c_transitions[i].num_children = petriNet.transitions[i].childs.size();
c_transitions[i].children = petriNet.transitions[i].childs.data();
c_transitions[i].parents = petriNet.transitions[i].parents.data();
}
c_petriNet->num_nodes = num_nodes;
c_petriNet->num_transitions = num_transitions;
c_petriNet->nodes = c_nodes;
c_petriNet->transitions = c_transitions;
return c_petriNet;
};
And use it in the main:
C_PetriNet* c_petriNet;
c_petriNet = Cpp_C_interface::convert_PetriNet(petriNet);
std::cout << "Test out: " << c_petriNet->num_nodes << std::endl;
std::cout << "Test out: " << c_petriNet->nodes[5].children[8] << std::endl;
std::cout << "Test out: " << c_petriNet->transitions[68].parents[1] << std::endl;
However, only the first output (num_nodes) is correct. If I print inside the function before returning, everything works fine. What can I do to return also the dynamic allocated memory?
The problem is that petriNet
is a local copy of the object that was passed to your function. You're saving pointers to the data()
of various vectors in petriNet
in the new C_Node
and C_Transition
that you're creating, but these pointers become invalid when the function returns.
If you change your function to take a reference, the pointers will remain valid as long as the caller's object is alive, but that's still fragile. What you really need to do is make copies of all the data. So you can use memcpy()
:
memcpy(c_nodes[i].children, petriNet.nodes[i].childs.data(), c_nodes[i].num_children * sizeof(*petriNet.nodes[i].childs.data());