美好的一天, 我刚刚开始学习c ++中的void指针,现在我正在编写二叉树,其中存储在每个节点中的值是指向值的void指针。
struct TreeNode
{
int count;
void* data;
TreeNode *left;
TreeNode *right;
};
问题出现在第一个方法添加方法中。 我的方法现在采用int参数并且不返回任何内容 在一开始我创建新节点。 为此,我需要将整数转换为void。 程序编译和第一个元素正确添加到root - 但是当我向方法发送另一个数字时它再次存储在root中。 所以,如果在主要我有类似的东西 tree.addToTree(12); tree.addToTree(13); 而不是它将第一个存储12而不是在其他声明之后(下面的代码)如何存储root->数据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);
}
}
因为我理解这是因为我使用&amp; num所以我的参数总是在一个地方撕裂而一个根“连接”到&amp; num它也会改变。
我试图找到解决方案,但没有成功。 有没有办法让cat int无效指针?
答案 0 :(得分:1)
我看到的一个问题是(不是答案,只是一个问题)......在函数
中void Tree::addToTree(int num)
{
if(root==NULL){
root= new TreeNode();
root->data=#
您要将自动变量的地址分配给data
。问题在于,一旦函数退出,该变量将不再存在(据说超出范围),因此您拥有所谓的悬空指针,即指向不再使用或不再用于指针所期望的原始目的的内存区域的指针。
您可以通过三种方式解决此问题。
root->data = (void *)num
(注意我将变量的值转换为一个void*
而不是变量的地址)。或者你可以,正如我看到Zac也建议的那样,root->data = new int(num);
。在这种情况下,您必须确保在销毁树时delete
内存你的另一个问题是你有评论的地方
//((int *)(root->data)) = num;//i tried to convert to void* in this way but it give me segmentation fault
这个失败的原因是因为root->data
此时只是一个指针......它不会指向任何地方(有意义的)。因此,当您尝试取消引用它时,您正在尝试访问某些“存在”的内存(指针为NULL或具有无效地址),因此您会出错。
以这种方式使用指针时,您需要创建一些内存,然后使指针指向该内存,例如root->data = new int;
。完成后,您可以在内存中为该位置指定一个值,例如*(root->data) = 1234;
答案 1 :(得分:1)
首先,非常非常将某些内容存储为void*
而不是使用强类型方法(例如模板)。当您将代码更改为
template<typename T>
TreeNode
{
TreeNode<T>* left;
TreeNode<T>* right;
T data;
};
那就是说,你遇到的问题是你存储的副本的地址一旦功能超出范围就会消失:
if(root==NULL)
{
root= new TreeNode();
root->data=# // PROBLEM!!!
root->left=NULL;
root->right=NULL;
}
问题行应该是:
root->data = new int(num);
完成后,您必须正确删除内存(例如,当您的树被破坏时)。
或者,如果您恰好位于sizeof(void*) == sizeof(int)
的系统上,则可以执行此操作
root->data = (void*)num;
将void*
成员简单地视为整数。这不适用于int
大于void*
的系统。
答案 2 :(得分:1)
首先,您应该决定是按值还是通过指针来存储数据。
在第一种情况下,指针只是没用,你可以使用如下模板:
template <typename T>
struct TreeNode
{
T data;
..
}
TreeNode<int> node;
这甚至可以使用指针(如T *data ... data = new int()
)。
如果您想存储指向数据的指针,您还可以使用带有类型参数的模板或使用共同的祖先类,然后使用所需类型将其子类化,例如:
class TreeData {
}
class TreeDataInt {
int value;
}
struct TreeNode
{
TreeData *data;
..
}
最后在int
指针内部记录void*
是不太鼓励的,因为你有很多其他更安全的工具,所以不鼓励使用C ++中的void*
来实现多态性。更可靠。
如果你真的想在int
内存储void*
,那么你应该使用intptr_t
类型,这是一个可转换为指针的整数。例如:
#include <cstdint>
intptr_t value = 50;
node->data = static_cast<void*>(value);
intptr_t value2 = static_cast<intptr_t>(node->data);
这会将整数的值直接保存为void*
内的地址。这意味着您无法取消引用指针本身。
顺便说一句root->data=&num
是错误的,因为您要为data
分配一个自动分配变量的地址,该变量在退出其范围时将变为无效。