我有一个二叉搜索树类BSTree。它曾经有一个成员,一个树的根节点。节点的类型由BSTNode结构定义。 但后来我添加了另一个成员,一个指向用于比较两个元素的函数的指针。那是问题开始的时候。
接口:
template <typename T>
struct BSTNode {
public:
struct BSTNode<T> *left;
struct BSTNode<T> *right;
T key;
BSTNode<T>(T element){ key = element;}
};
template <typename T>
class BSTree {
private:
BSTNode<T> *root;
int (*compare)(T el1, T el2); // this is the new member
public:
BSTree<T>(int (*cmp)(T el1, T el2)) {root = NULL; compare = cmp;}
//...
向树添加内容的函数BSTree :: add使用指向根节点的指针。添加新的'compare'成员后,此功能中断。该函数从如下开始(它添加了一些printf行以找到崩溃的确切行):
功能定义:
template <typename T>
BSTNode<T>* BSTree<T>::add(T element) {
BSTNode<T> **node;
printf("&root = %p\n", &root);
printf("node = %p\n", node); //must be NULL
printf("compare = %p\n", (int(*)(T, T))compare); //address stored in fn pointer
node = &root; /////////// THIS PART produces the segmentation fault. ////////
printf("succeeded");
//...
函数调用(在main中):
BSTree<int> bst(&stdcomp); //stdcomp is the integer compare function
bst.add(6);
//...
输出:
&root = 0x7fff5fbff8c0
node = 0x0
compare = 0x100001325
Segmentation fault
对我来说特别令人费解的是,分配失败了,即使它没有取消引用存储在我的指向指针'节点'中的地址,'node'是一个局部变量而且没有被解除引用;我不知道非法内存访问的位置。我试图将节点初始化为几个文字值(例如NULL或0x1),并且它们不会产生错误。它只是在我将函数指针添加到类后才失败,该类根据打印的内容分配了正确的地址。是否与滥用模板有关?
顺便说一句,BSTree模板用typenames int和const char *实例化,每个模板都有一个正确分配的不同比较函数(我认为)。我测试了他们的添加功能,两者都产生了错误。
答案 0 :(得分:1)
在printf("succeeded");
调用之后,您的分段错误可能会发生,因为printf不包含换行符,并且您的输出可能处于行缓冲模式。所以字符串'succeeded'进入stdout缓冲区但没有出现在屏幕上。将stdout置于无缓冲模式,或在字符串中粘贴\n
。或者更好的是,在每个printf之后粘贴fflush(stdout);
,这样无论stdout缓冲模式如何,缓冲区都会被刷新。
答案 1 :(得分:0)
printf("compare = %p\n", (int(*)(T, T))compare);
这是未定义的行为 - printf
的{{1}}需要指向%p
的指针,但是您传递了一个函数指针。函数指针不能转换为void
。
我建议你在调试器中运行你的程序,看看它真的是你怀疑导致错误的任务。它可能是一些堆栈粉碎等。赋值本身应该只调用引用堆栈的操作。