2017-03-13 5 views
-3

編集1
Jonathan Lefflerによって示唆されるように、私は今、アンダースコアとも->周りの削除スペースで始まる名前を使用していません。
________________________________________________________________________________アンロード()再帰CとSegfault(データベースのようなトライ)CS50のpset5

再帰関数を持つ構造体を解放しようとしたとき、私はセグメンテーションフォルトを取得しています。

//creating new trie data ctructure 
typedef struct dict 
{ 
    bool is_word; 
    struct dict *children[ALPHABET+1]; 
} 
node; 

辞書を格納するために使用され、スペルチェッカで使用されます。

は、ここに私の構造体です。プログラムの最後に、割り当てられたすべてのメモリを解放する必要があります。

ここに私が書いた機能があります。それは自分自身を呼び出し、ピースごとに無料でトライする必要があります。しかし、それは私自身に何回か呼び出された後にセグメンテーションを与える。

bool unload(void) 
{ 
    // Check if root 
    if (temp == root) 
    { 
     for (int i = 0; i < ALPHABET+1; i++) 
     { 
      if (!temp->children[i] && i != ALPHABET) 
      { 

      } 
      else if (!temp->children[i] && i == ALPHABET) 
      { 
       free(temp); 
       return true; 
      } 
      else if(temp->children[i]) 
      { 
       temp = temp->children[i]; 
       unload(); 
      } 
     } 
    } 
    else 
    { 
     for (int i = 0; i < ALPHABET+1; i++) 
     { 
      if (!temp->children[i] && i != ALPHABET) 
      { 

      } 
      else if (!temp->children[i] && i == ALPHABET) 
      { 
       temp1 = temp; 
       temp->children[i] = temp; 
       free(temp1); 
       return true; 
      } 
      else if (temp->children[i]) 
      { 
       temp = temp->children[i]; 
       unload(); 
      } 
     } 
    } 
    return false; 
} 

root、temp、temp1がグローバルであるとします。それらのすべてはstruct _dictです。そして、関数が初めて呼び出された時、temp == root。

+0

ようこそスタックオーバーフロー。 [About]ページと[Ask]ページをもう一度お読みください。さらに重要なことに、 MCVE([MCVE])の作成方法をお読みください。 ここでMCVEにとって重要な要件の1つは、問題を引き起こすコンパクトな入力値セットです。それは欠けているようだ。 –

+0

アドバイスをいただきありがとうございます!今はもっと良いと思う? –

+0

あなたのコードは、グローバル変数がなぜ悪い考えであり、逆効果をもたらすのかを実証しています。関数に解放されるノードを渡す必要があります。最初の呼び出しはルートノードを通過します。この関数は、グローバル変数にアクセスする必要はありません。 –

答えて

0

あなたのコードは、グローバル変数が悪い考えであり、逆効果をもたらす理由を示しています。関数に解放されるノードを渡す必要があります。最初の呼び出しはルートノードを通過します。この関数は、グローバル変数にアクセスする必要はありません。

また、ドット.と矢印->は非常に厳密にバインドされており、周囲にスペースを入れないでください。また、アンダースコアで始まる名前は基本的に実装で使用するために予約されています。 The full details are more nuancedそれよりはるかに多いわけではありません。あなたが発明した名前の下線を避けるのが最も簡単です。システム提供施設にアクセスする場合にのみ使用してください。

このコードは、nodeを割り当てるコードがすべてのポインタがnullであることを保証していると仮定して、必要な処理を行います。

#include <stdlib.h> 
#include <stdbool.h> 
enum { ALPHABET = 26 }; 
typedef struct dict 
{ 
    bool is_word; 
    struct dict *children[ALPHABET+1]; 
} node; 

void unload(node *item); 

void unload(node *item) 
{ 
    for (int i = 0; i < ALPHABET+1; i++) 
    { 
     if (item->children[i] != 0) 
      unload(item->children[i]); 
    } 
    free(item); 
} 

コードがitemがすべてでそれを使用する前に、NULLであるかどうかをテストするために改訂することができます。ループ内の条件は厳密には必要ではありませんが、ノードが割り当てられる前に呼び出された場合、全体の関数はより弾力性があります。示され、それはこれらのかなり厳しい警告オプション(MacOSのシエラ10.12.3を実行しているMac上でGCC 6.3.0)できれいにコンパイルするよう

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes \ 
>  -Wstrict-prototypes -Wold-style-definition -c tr47.c 
$ 

このコードが実行されていません。私はこのCS50問題について、他の人々の変種にも同様の機能を書いてきました。これ以上複雑である必要はありません。

+0

実際には割り当てごとに、私はアンロード宣言( 'bool unload(void)')を変更することになっていないので、グローバル変数が使われています。 ノード割り当て部分は次のようになります。 ノード* getnode(void) { ノード* newnode = malloc(sizeof(node)); if(newnode!= NULL) { newnode - > is_word = false;for(int i = 0; i <(ALPHABET + 1); i ++) newnode - > children [i] = NULL; } return newnode; } –

+0

OK:書き込み: 'bool unload(void){real_unload(root);真を返します。 } 'を呼び出し、私が' real_unload() 'と書いた関数の名前を変更してください。あるいは、次のように使うこともできます: 'bool unload(void){if(root == NULL)falseを返します。 real_unload(ルート);真を返します。 } '。 'temp'というグローバル変数は作成しないでください。必要以上にグローバルを使用しないでください。図のように、仕事をきれいにしてください。あなたは指定されたもの以外の関数を書くことが許されていませんか?その場合、あなたはサディスティックな家庭教師を持っています。これはCS50です。あなたが引用しているルールについて確かですか?誰も同じようなコードを解放する前に苦情を申し立てていませんでしたが、... –

+0

いいえ、私は特定の機能(アンロードなど)の実装を変更できません。私たちは、私たちが助けると思っている機能を自由に書くことができます。だから私はあなたのこのトリックを覚えています! –