【问题标题】:Assignment of address to a pointer-to-pointer gives segmentation fault将地址分配给指针到指针会导致分段错误
【发布时间】:2011-01-15 01:41:59
【问题描述】:

我有一个二叉搜索树类,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 向树添加内容,它使用指向根节点指针的指针。在我添加了新的“比较”成员后,这个功能就坏了。该函数开始如下(我添加了一些 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'中的地址,并且'node'是一个局部变量并且没有被取消引用;我不知道非法内存访问发生在哪里。我尝试将节点初始化为几个文字值(例如 NULL 或 0x1),但它们没有产生错误。只有在我将函数指针添加到类后它才失败,根据打印的内容,它被分配了正确的地址。是否与滥用模板有关?

顺便说一下,BSTree 模板是用类型名 int 和 const char* 实例化的,每个都有一个正确分配的不同比较函数(我认为)。我测试了他们的 add 函数,都产生了错误。

【问题讨论】:

  • 我不认为您有可能被触发的 operator= 过载?
  • 不。我没有重载任何运算符,我的类也没有超类:S
  • 你为什么有BSTNode&lt;T&gt; **node?我不明白为什么需要指向指针的指针。
  • 指针到指针是为了能够修改节点。此函数向树中添加内容,它找到具有空指针的适当叶节点,并将该指针的值更改为新节点
  • 看起来你的错误在别处。我测试了您的代码片段,它工作正常(也可以使用 valgrind 干净运行)。

标签: c++ pointers segmentation-fault function-pointers


【解决方案1】:

您的分段错误可能发生在printf("succeeded"); 调用之后,因为 printf 不包含换行符,并且您的输出可能处于行缓冲模式。所以字符串'succeeded'进入标准输出缓冲区但没有出现在屏幕上。要么将标准输出置于无缓冲模式,要么在字符串中粘贴\n。或者更好的是,在每次 printf 之后粘贴fflush(stdout);,这样缓冲区就会被刷新,而不管标准输出缓冲模式如何。

【讨论】:

  • 或者他可以像其他人一样使用调试器。我不明白他为什么要打印查找段错误这样简单的事情。
【解决方案2】:
printf("compare = %p\n", (int(*)(T, T))compare);

这是未定义的行为 - printf%p 需要一个指向 void 的指针,但您传递了一个函数指针。函数指针不能转换为void*

我建议你在调试器中运行你的程序,看看你怀疑是不是真的是作业导致了错误。它可能是一些堆栈粉碎等。赋值本身应该只调用引用堆栈的操作。

【讨论】:

  • 事实证明,函数指针在大多数架构上都可以转换为 void,但无论如何都是好点。如果我看到一个没有明确演员表的人,我仍然会不寒而栗。但是,这看起来像一个指向成员函数的指针,它绝对不可转换并且可能会使堆栈失衡。
  • 是的,我知道这样做很糟糕,抱歉。它在我的拱门中工作,它是一个指向非成员函数的指针,别担心,我确定它不是一个胖指针——但我很清楚我不应该做出这些假设......这个问题可能确实与堆栈有关,因为我几乎可以肯定是对局部变量的赋值导致程序崩溃。
  • @user451963:几乎确定?你是在调试器下运行的吗?崩溃的确切指令是什么?在add的反汇编中它在哪里?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-03-02
  • 1970-01-01
  • 2021-05-25
  • 1970-01-01
  • 2016-01-02
  • 1970-01-01
  • 2021-05-08
相关资源
最近更新 更多