Reputation: 99
Good day, I just started to learn void pointers in c++ and now I'm writing binary tree where value stored in each node is void pointer to a value.
struct TreeNode
{
int count;
void* data;
TreeNode *left;
TreeNode *right;
};
The problem occurred in very first method-add method. my method now takes int a a parameter and return nothing At the very beginning i create new node. To do that I need to cast integer into void. Program compiles and first element adds to root correctly-however then when i send another number to method it stores in root again. so if in main i have something like tree.addToTree(12); tree.addToTree(13); than it would store 12 first and than right after else statement(code below)how that root->data i 13.
void Tree::addToTree(int num)
{
if(root==NULL){
root= new TreeNode();
root->data=#
//((int *)(root->data)) = num;//i tried to convert to void* in this way but it give me segmentation fault
root->left=NULL;
root->right=NULL;
}
else{
//here root value is already changed
int *intPtr = static_cast<int*>(root->data);
cout << "key2" << *intPtrT << endl;
//TreeNode* current= insert(num,root);
}
}
as i understood thats because i use &num so my parameter always tore in one place and a root is "connected" to &num it change as well.
I tried to find solution but was unsuccessful. Is there a way to cat int to void pointer?
Upvotes: 1
Views: 20406
Reputation: 4515
One problem I see is this (not the answer, just a problem)... in the function
void Tree::addToTree(int num)
{
if(root==NULL){
root= new TreeNode();
root->data=#
You are assigning the address of an automatic variable to data
. The trouble is that as soon as the function exits, this variable will no longer exist (it is said to go out of scope) and so you have what's known as a dangling pointer, i.e., a pointer that points to an area of memory that is no longer used or is no longer used for the original purpose that the pointer expects.
You could fix this in three ways.
root->data = (void *)num
(note I cast the value of the variable to a void*
and not the address of the variable). Or you could, as I see Zac has suggested too,root->data = new int(num);
. In this case you must make sure to delete
the memory when you destroy the treeThe other bit of you question where you have the comment
//((int *)(root->data)) = num;//i tried to convert to void* in this way but it give me segmentation fault
The reason this fails is because root->data
at this point is just a pointer... it doesn't point anywhere (meaningful) yet. Thus when you try to dereference it, you are trying to access some memory that does "exist" yet (either pointer is NULL or has an invalid address), and so you seg fault.
When using a pointer in this way you need to create some memory and then make the pointer point to that memory, e.g. root->data = new int;
. Once you have done that, you can then assign a value to that location in memory, e.g., *(root->data) = 1234;
Upvotes: 1
Reputation: 133567
First of all you should decide if you want to store data by value or by a pointer to it.
In first case having a pointer is just useless, you could use a template like:
template <typename T>
struct TreeNode
{
T data;
..
}
TreeNode<int> node;
This will work even with pointers (like T *data ... data = new int()
).
In case you want to store a pointer to data you can also use a template with a type parameter or use a common ancestor class and then subclass it with the required types, eg:
class TreeData {
}
class TreeDataInt {
int value;
}
struct TreeNode
{
TreeData *data;
..
}
Lastly storying an int
inside a void*
pointer is something not so encouraged, using void*
in C++ to achieve polymorphism is discouraged in general since you have many other tools which are safer and more reliable.
If you really want to store an int
inside a void*
then you should use the intptr_t
type which is an integer that is convertible to a pointer. Eg:
#include <cstdint>
intptr_t value = 50;
node->data = static_cast<void*>(value);
intptr_t value2 = static_cast<intptr_t>(node->data);
This will save the value of the integer directly as an address inside the void*
. This means that you can't dereference the pointer itself.
By the way root->data=&num
is wrong since you are assigning to data
the address of an automatic allocated variable which will become invalid when exiting its scope.
Upvotes: 1
Reputation: 15872
First of all, there are very very few reasons to store something as a void*
instead of using a strongly typed method (e.g. template). Your entire problem goes away fairly quickly when you change your code to
template<typename T>
TreeNode
{
TreeNode<T>* left;
TreeNode<T>* right;
T data;
};
That said, the problem you have is that you are storing the address of a copy that will go away once the function goes out of scope:
if(root==NULL)
{
root= new TreeNode();
root->data=# // PROBLEM!!!
root->left=NULL;
root->right=NULL;
}
The problem line should be:
root->data = new int(num);
And you will have to properly delete the memory when you are done with it (e.g. when your tree is being destructed).
Alternatively, if you happen to be on a system where sizeof(void*) == sizeof(int)
, you can do this
root->data = (void*)num;
Which will simply treat the void*
member as an integer. This does not work on systems where int
is larger than void*
.
Upvotes: 1