C++ C++;避免检查双指针持有的未初始化值
解决C++ C++;避免检查双指针持有的未初始化值,c++,pointers,initialization,valgrind,double-pointer,C++,Pointers,Initialization,Valgrind,Double Pointer,解决 问题最终源于数据结构的设计。要删除根元素,必须有一个堆分配的(新的)指针指向它,这在原始情况下是不可能的,因为数据直接由树保存。现在有一个节点结构保存所有数据,树类包含所有方法和根指针 我有一个双指针target\u address初始化为NULL,我以后必须检查*target\u address是否为NULL。在这两者之间,函数保证*target_address指向未初始化的值,但Valgrind一直抱怨我只有在删除根元素时才读取未初始化的值 树_delete也抱怨未初始化值;我敢肯
问题最终源于数据结构的设计。要删除根元素,必须有一个堆分配的(新的)指针指向它,这在原始情况下是不可能的,因为数据直接由树保存。现在有一个
节点
结构保存所有数据,树类包含所有方法和根指针我有一个双指针
target\u address
初始化为NULL
,我以后必须检查*target\u address
是否为NULL。在这两者之间,函数保证*target_address
指向未初始化的值,但Valgrind一直抱怨我只有在删除根元素时才读取未初始化的值
树_delete也抱怨未初始化值;我敢肯定它也在抱怨*目标地址
void tree<T>::tree_delete(tree<T>** target_address) {
tree<T>* target = *target_address;
// first case: no left subtree, replace with right subtree (or NULL for a leaf)
if (!target->left)
*target_address = target->right;
// second case: no right subtree, replace with left subtree
else if (!target->right)
*target_address = target->left;
// third case: both subtrees, find second largest by taking rightmost left tree
else {
tree<T>** second_largest_address = &target->left; // start at target's left tree
while ((*second_largest_address)->right) // keep going right
second_largest_address = &((*second_largest_address)->right);
// reached the rightmost left
tree<T>* second_largest = *second_largest_address;
*target_address = second_largest; // delete target by replacing it with second largest
// second largest guranteed to not have a right subtree, so can treat as case 2 by shifting
*second_largest_address = second_largest->left;
second_largest->left = target->left;
second_largest->right = target->right;
}
delete target;
}
类似于的代码,如果(!this)返回空代码>非常可疑。这是一个无操作,并指示其他地方未定义的行为。难怪Valgrind报告您的代码出现问题
更糟糕的是,请查看树中的代码\u find
:
tree<T>* root = this; // <-- ensures *target_address points to stack variable !
tree<T>** target_address = &root; // Set out pointer to stack variable
tree*root=this;//能否显示tree::data
的定义?tree\u find
如果数据与第一个节点匹配,则返回指向堆栈变量的指针tree*root
是堆栈变量,tree**target\u address=&root
-堆栈变量的地址,*target\u address\u handle=target\u address代码>-将不存在的变量的地址发送回调用方。我不太清楚为什么要返回指向所需节点的指针的地址,而不仅仅是指向所需节点的指针!树数据只是T数据
,其他属性是Tree*left,*right
typeid(T)==typeid(T)
那么总是正确的@MattMcNabb啊对,这证实了我的怀疑。。。想想看,我不认为我需要三个指针;我会尝试摆脱它,看看它是否仍然有效,是的,typeid(T)=typeid(T)。。。忘记C++是强类型的,可能有人可以尝试在不同类型的树上搜索
void tree<T>::tree_delete(tree<T>** target_address) {
tree<T>* target = *target_address;
// first case: no left subtree, replace with right subtree (or NULL for a leaf)
if (!target->left)
*target_address = target->right;
// second case: no right subtree, replace with left subtree
else if (!target->right)
*target_address = target->left;
// third case: both subtrees, find second largest by taking rightmost left tree
else {
tree<T>** second_largest_address = &target->left; // start at target's left tree
while ((*second_largest_address)->right) // keep going right
second_largest_address = &((*second_largest_address)->right);
// reached the rightmost left
tree<T>* second_largest = *second_largest_address;
*target_address = second_largest; // delete target by replacing it with second largest
// second largest guranteed to not have a right subtree, so can treat as case 2 by shifting
*second_largest_address = second_largest->left;
second_largest->left = target->left;
second_largest->right = target->right;
}
delete target;
}
==25887== Conditional jump or move depends on uninitialised value(s)
==25887== at 0x401764: tree<int>::remove(int) (in /home/johnson/Code/tree/treetest)
==25887== by 0x4013AA: main (in /home/johnson/Code/tree/treetest)
==25887== Uninitialised value was created by a stack allocation
==25887== at 0x40175A: tree<int>::remove(int) (in /home/johnson/Code/tree/treetest)
==25887==
After reading *target tree address
Before read
==25887== Use of uninitialised value of size 8
==25887== at 0x401A75: tree<int>::tree_delete(tree<int>**) (in /home/johnson/Code/tree/treetest)
==25887== by 0x40178E: tree<int>::remove(int) (in /home/johnson/Code/tree/treetest)
==25887== by 0x4013AA: main (in /home/johnson/Code/tree/treetest)
==25887== Uninitialised value was created by a stack allocation
==25887== at 0x401A46: tree<int>::tree_delete(tree<int>**) (in /home/johnson/Code/tree/treetest)
==25887==
==25887== Use of uninitialised value of size 8
==25887== at 0x401AA5: tree<int>::tree_delete(tree<int>**) (in /home/johnson/Code/tree/treetest)
==25887== by 0x40178E: tree<int>::remove(int) (in /home/johnson/Code/tree/treetest)
==25887== by 0x4013AA: main (in /home/johnson/Code/tree/treetest)
==25887== Uninitialised value was created by a stack allocation
==25887== at 0x401A46: tree<int>::tree_delete(tree<int>**) (in /home/johnson/Code/tree/treetest)
==25887==
==25887== Use of uninitialised value of size 8
==25887== at 0x401AF2: tree<int>::tree_delete(tree<int>**) (in /home/johnson/Code/tree/treetest)
==25887== by 0x40178E: tree<int>::remove(int) (in /home/johnson/Code/tree/treetest)
==25887== by 0x4013AA: main (in /home/johnson/Code/tree/treetest)
==25887== Uninitialised value was created by a stack allocation
==25887== at 0x401A46: tree<int>::tree_delete(tree<int>**) (in /home/johnson/Code/tree/treetest)
==25887==
==25887== Invalid read of size 8
==25887== at 0x401AF5: tree<int>::tree_delete(tree<int>**) (in /home/johnson/Code/tree/treetest)
==25887== by 0x40178E: tree<int>::remove(int) (in /home/johnson/Code/tree/treetest)
==25887== by 0x4013AA: main (in /home/johnson/Code/tree/treetest)
==25887== Address 0x801f0fc36d is not stack'd, malloc'd or (recently) free'd
tree<T>* root = this; // <-- ensures *target_address points to stack variable !
tree<T>** target_address = &root; // Set out pointer to stack variable