aldebaran
aldebaran

Reputation: 99

Casting int to void pointer

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

Answers (3)

Jimbo
Jimbo

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=&num;

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.

  1. If you only want to store ints or any data type whose width is le that sizeof(void *), you could do 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,
  2. Create a copy of the variable and store the copies address. root->data = new int(num);. In this case you must make sure to delete the memory when you destroy the tree
  3. Use templates as others have suggested (this is the better way) - I'll leave this point as others have covered it.

The 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

Jack
Jack

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

Zac Howland
Zac Howland

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=&num; // 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

Related Questions