2011-01-15 10 views
0

私はバイナリ検索ツリークラスBSTreeを持っています。これは、ツリーのルートノードである単一のメンバーを持つことでした。ノードのタイプは、BSTNode構造体によって定義されます。 しかし、私は別のメンバー、2つの要素を比較するために使用される関数へのポインタを追加しました。それは問題が始まったときです。ポインタへのポインタの代入によってセグメント化エラーが発生する

インタフェース:

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 ::追加し、ツリーにものを追加して、ルートノードへのポインタへのポインタを使用しています。私は新しい '比較'メンバーを追加した後、この関数は壊れました。

関数定義:

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"); 
    //... 

ファンクションコール(メインで):

BSTree<int> bst(&stdcomp); //stdcomp is the integer compare function 
bst.add(6); 
//... 

次のように関数が始まる(それは私がクラッシュした正確なラインを見つけるために、追加いくつかのprintfラインを持っています)出力:

&root = 0x7fff5fbff8c0 
node = 0x0 
compare = 0x100001325 
Segmentation fault 

特に困惑しているのは、割り当てが失敗し、 hは、ポインタへのポインタ 'node'に格納されているアドレスを逆参照しません。また、 'node'はローカル変数であり、逆参照されません。私は、不正なメモリアクセスがどこで発生するのかわかりません。ノードをいくつかのリテラル値(NULLや0x1など)に初期化しようとしましたが、エラーは発生しませんでした。私はクラスに関数ポインタを追加した後に失敗しただけです。クラスには、印刷されたものに応じて正しいアドレスが割り当てられます。テンプレートの誤用とは何か関係がありますか?

ちなみに、BSTreeテンプレートはtypemames intとconst char *でインスタンス化されていますが、それぞれが正しく割り当てられた異なる比較関数を持っています(私は思っています)。私はそれらの追加機能をテストし、両方とも障害を生成しました。 printf%pvoidへのポインタを期待していますが、関数ポインタを渡す -

+0

私は演算子=のオーバーロードが発生しているとは思わないでしょうか? – Aron

+0

nope。私はすべての演算子をオーバーロードしていないし、私のクラスはスーパークラスを持っていない:S –

+0

なぜ 'BSTNode ** node'があるのですか?ポインターからポインタへのポインタが必要な理由はわかりません。 –

答えて

0
printf("compare = %p\n", (int(*)(T, T))compare); 

これは未定義の動作です。関数ポインタはvoid*に変換できません。

デバッガでプログラムを実行することをお勧めします。これは、本当に障害の原因と思われる割り当てであることがわかります。スタックスワッシュなどのようなものかもしれません。割り当て自体は、スタックを参照する操作のみを呼び出す必要があります。

+1

関数ポインタはほとんどのアーキテクチャでは空白に変換可能ですが、とにかく良い点になります。私は明白なキャストなしで私が見た場合私はまだ震えるだろう。しかし、それは間違いなく変換可能ではなく、スタックのアンバランスになるかもしれないメンバ関数へのポインタのように見えます。 – Joshua

+0

ええ、私はそれが恐ろしいことだと知っています、申し訳ありません。それは私のアーチで動作し、それは非メンバ関数へのポインタです、心配しないで、私はそれが太いポインタではないと確信しています - しかし、私はこれらの前提をすることになっていないとよく分かっています...この問題は実際にはスタックに関係している可能性があります。なぜなら、プログラムをクラッシュさせるのはローカル変数への割り当てだと思っているからです。 –

+0

@ user451963:ほとんど確実ですか?デバッガで実行しましたか?クラッシュする正確な指示は何ですか?また、 'add 'の逆アセンブリではどこにありますか? – jpalecek

1

ことのprintfは改行が含まれていないとしてあなたのセグメンテーションフォールトはproabably、printf("succeeded");呼び出しの後に起こっている、とあなたの出力は、ラインバッファモードである可能性があります。したがって、文字列 'succeeded'はstdoutバッファに入っていますが、画面には表示されません。 stdoutをバッファなしモードにするか、文字列に\nを置きます。または、stdoutバッファリングモードに関係なくバッファがフラッシュされるように、各printfの後にfflush(stdout);を貼り付けます。

+0

または彼は他の誰かのようにデバッガを使うことができます。なぜ彼はセグメンテーションを見つけるのと同じくらい単純なことをprintfingしているのか分かりません。 –

関連する問題