循環的な二重リンクリスト内のノードを再帰的にカウントしようとした際にエラーが発生しました

countの実装は次のとおりです。

int count(node *start)
{
    static int l ;
    node *current;            /* Node for travelling the linked list*/
    current=start;
    if(current->next!=start)
    {
        l = 1 + count ( current->next ) ;
        return ( l ) ;
    }


    else
    {
        return(1);
    }
}

ここで私はそれを呼び出す主な機能の断片です:

void main()
{
    node *head;
printf ( "Length of linked list = %d", count ( head ) ) ;
}

ここに構造があります:

struct cirdoublelinklist
{
    struct cirdoublelinklist *prev;  /** Stores address of previous node **/
    int value;                   /** stores value **/
    struct cirdoublelinklist *next;  /** stores address of next node **/
};

/** Redefining list as node **/
  typedef struct cirdoublelinklist node;

実行中にリストの長さを確認しようとすると、バインドされていないメモリでクラッシュします。これで私を助けてください、私はこれで長い間今働いています。

最初のノードを追加する方法:

void initialize(node *start)
{
    start->prev=start;
    printf("\nEnter Value\n");
    scanf("%d",&start->value);
    start->next=start;
}

指定された場所の後に続くノードを追加するメソッド:

void insert_after(node *start)
{
    int num;                  /* value for inserting a node */
    int flag=0;
    node *newnode;            /* New inputed node*/
    node *current;            /* Node for travelling the linked list*/
    newnode=(node*)malloc(sizeof(node));
    printf("\nEnter the value after which you want to insert a node\n");
    scanf("%d",&num);
    init(newnode);
    current=start;
    while(current->next!=start)
    {

        if(current->value==num)
        {
            newnode->next=current->next;
            current->next->prev=newnode;
            current->next=newnode;
            newnode->prev=current;
            flag=1;
        }
        current=current->next;
    }
    if(flag==0 && current->next==start && current->value==num)
    {
        /***  Insertion checking for last node  ***/
        newnode->next=current->next;     /* Start is being copied */
        current->next->prev=newnode;
        current->next=newnode;
        newnode->prev=current;
        flag=1;
    }
    if(flag==0 && current->next==NULL)
        printf("\nNo match found\n");
} 
0
なぜ l を静的にしましたか?これは、関数が完全に再入可能であることを防ぎます。これは通常、適切な再帰の要件です。
追加された 著者 Ignacio Vazquez-Abrams,

4 答え

まあ、問題は、あなたがNULLポインターでメインの関数を呼び出すことです。 Infact node * head; は宣言されていますが、決して何かに割り当てられません。したがって、この行を実行すると:

if(current->next!=start)

the program crashes because it will check for NULL->next that, obviously, doesn't exist.

1
追加された
@ user1017072この場合、データを追加する関数を表示する必要があります。さらに、静的int l行を削除します。それは役に立たず、ちょうど1 + count(current-> next)を返すときにifを変更します。再帰的な機能を持つ適切な方法です。
追加された 著者 Aurelio De Rosa,
基本的にデータ値をノードに挿入するメソッドもあります。しかし、私は新しいノードを作成した後でさえも失敗するようです。最初のノードでは、適切な長さの1を与えます(つまり、elseブロックに移動します)。しかし、2番目のノードでは、if(current-> next!= start)に達するとクラッシュします。私はノードを作成している関数のいくつかの初期化?ご協力ありがとうございました
追加された 著者 user1017072,
こんにちは、私は最初のノードを挿入するメソッドとその後のノードを使用して質問を編集しました。私はあなたが指定した静的を削除しようとしましたが、同じメモリ不足の問題で失敗します。これ以上の提案はありますか?あなたの時間とサポートをありがとう
追加された 著者 user1017072,

Every time you call count, it has a new start, so current->next!=start is always comparing a node to its successor, which will only ever end if the list has length 1. What you most likely want to do is have two functions:

int count(node *start)
{
    if(start == NULL)
        return 0;
    return count_helper(start, start);
}

int count_helper(node *start, node *current)
{
    static int l;
    if(current->next!=start)
    {
        l = 1 + count (start, current->next);
        return ( l ) ;
    }
    else
    {
        return(1);
    }
}

他の人が触れたように、静的変数は必要ありません。私が count_helper と呼んでいるものを書く良い方法は、次のようなものです:

int count_helper(node *start, node *current)
{
    if(current->next!=start)
    {
        return 1 + count (start, current->next);
    }
    else
    {
        return 1;
    }
}

最後に、より効率的な実装は非再帰的です。

int count(node *start)
{
    if(start == NULL)
        return 0;
    node *current = start->next;
    int c = 1;
    while(current != start)
    {
        c++;
        current = current->next;
    }
    return c;
}
1
追加された
@ user1017072長さ= 0の場合、非再帰バージョンの編集を書き留めておいてください。また、あなたがあなたの質問に最もよく答えた答えを受け入れると助けになるでしょう。
追加された 著者 Aaron Dufour,
@CVega良いキャッチ。この回答は覚えていませんが(2歳!)、 c1 への初期化に基づいて、私の意図は current >を start-> next で開始します。それは理にかなっていますか?
追加された 著者 Aaron Dufour,
@ Aaron-dufour私は非再帰的なバージョンが間違っていると思います。 while ループ現在開始が等しいので、ループに入る前にdo-whileループにする必要があります。
追加された 著者 Carlos Vega,
はい、修正済みです;)
追加された 著者 Carlos Vega,
本当に助けてくれてありがとうございました。今私は自分のコンセプトをクリアしました
追加された 著者 user1017072,

insert_after関数でポインタを開始するポインタを渡す必要があります

void insert_after(node **start)

の代わりに

void insert_after(node *start)

それ以外の場合は、* startのローカルコピーを更新するだけです。

同様に初期化

void initialize(node **start)
1
追加された

簡単に言えば、再帰呼び出しは元の開始ノードを認識しません。 2番目の node * 引数を追加し、それを介して開始ノードを渡す必要があります。

0
追加された
関数プロトタイプで。関数呼び出しで。
追加された 著者 Ignacio Vazquez-Abrams,
こんにちはIgnacio、どこに2番目のノードを追加する必要がありますか、どのように開始ノードを渡す必要があります。私はノブのように聞こえて申し訳ありませんが、それを修正する方法を私に示すことができますか、私は理解できません。ご助力ありがとうございます
追加された 著者 user1017072,