1

次のコードは、ポインターを理解する上で linusから取得したものです。

typedef struct list_entry {
   int val;
   struct list_entry *next;
} list_entry;    


list_entry **pp = &head; /* pointer to a pointer */
list_entry *entry = head;

while (entry) {
    if (entry->val == to_remove)
        *pp = entry->next;            //6      

    pp = &entry->next;                //8   
    entry = entry->next;
} 

6行目と8行目を理解できる人はいますか? entry->val == to_remove の場合、行 6 が評価され、*pp が削除後の次のエントリになると、その後行 8 は何をしますか? 現在のエントリは削除されています。このエントリを 8 行目で再利用するにはどうすればよいですか?

また、*pp はポインタ pp の値、&entry->next は pp のアドレスを意味することを理解していますが、いつ * を使用し、いつ & を使用するかについて常に混乱しています。具体的には、6行目は次のようになります。

pp = &entry->next; 

8 行目は次のようになります。

*pp= entry->next; 

そうでない場合、なぜですか?

4

4 に答える 4

1

アップデート:

ブログのコードは不完全で、削除される要素は 1 つだけであり、free は不要であると想定しています。削除する連続する要素が 2 つ以上ある場合、シーケンスの 2 番目の要素は削除されません。

正しいコードは次のとおりです。これは、ノードを解放する必要がないことも前提としています。

while (entry) {
    if (entry->val == to_remove)
        *pp = entry->next;           
    else
        pp = &entry->next;  

    entry = entry->next;
} 

そして、ノードを解放する必要がある場合:

while (entry) 
{
    if(entry->value == to_remove  )
    {
        *pp = entry->next;            
        free( entry ) ;
        entry = *pp ;
    }
    else
    {
        pp = &entry->next;               
        entry = entry->next;
    }
} 



構造全体を書くことは、これを理解するのに本当に役立ちます。

struct Node
{
    int val ;
    struct Node* next ; //hint, this has an address too.

} ;

トリックはステートメントにあります

pp = &entry->next ;

これはノードを指しているように見えますnextが、実際には現在のノードのポインターのアドレスを取得しているだけです。大きな違い!

したがって、最初の例pp = &entry->next ;とほぼ同じですが、唯一の違いは、 current全体を指すのではなく、 current prev = entry;のメンバーのアドレスを指すことです。nextstruct Nodestruct Node

于 2014-10-20T18:30:15.800 に答える
0

ここで何が起こっていますか:

list_entry **pp = &head; /* pointer to a pointer */
list_entry *entry = head;

// we start with entry being head and pp being an address of head
while (entry) {
// while there is a list_entry which is not NULL...
    if (entry->val == to_remove)
        // if entry points to value that should be removed, 
        // then store the address of the next entry in whatever pp points to now
        // (which effectively means removing that entry)
        *pp = entry->next;            //6      
    // pp is now an address of the next entry
    pp = &entry->next;                //8   
    // move to the next entry to start the next iteration
    entry = entry->next;
} 

このコードの動作: リストを調べて、削除済みとしてマークされたすべてのエントリを削除します。

それはどのようにそれを行います:

  • 本来、pp頭を指す。

  • 頭から始めて、リストを調べます。

  • 現在のエントリが指す値が「削除済み」としてマークされている場合は常に、pp現在のリスト エントリのアドレスに次のリスト エントリのアドレスを格納します。が頭を指していた場合pp、それは頭が破棄され、次の要素を指し始めることを意味します。リストの途中にある要素を指していた場合pp、それはこの要素が削除されたことを意味します (前の要素が削除された要素の後の要素を指すため)。

  • それが完了すると、entryポイントを移動してリスト内の次の値を調べます。

于 2014-10-20T19:43:34.463 に答える
0

このサンプル コードでは、pp は前のチェーンの「次の」メンバーのアドレスを格納するため、現在のチェーンが削除対象としてマークされている場合、前のチェーンの「次の」メンバーを変更して、削除されるチェーンの「次」。間接的な変更は、* 演算子を適用することによって行われます。

コードが目的の効果を達成できないため、6行目と8行目を質問どおりに変更することはできません。

  1. 前の (またはヘッド) チェーンの「次の」メンバーのアドレスを保持します。

  2. 現在のチェーンが削除対象としてマークされているかどうかを確認します。

  3. その場合は、pp 参照を使用して、前のチェーンの「次の」メンバーを間接的に操作して、現在の「次の」メンバーを指すようにします。したがって、実際には、リンクされたリストは、その整合性を維持しながら現在のチェーンをスキップします。

于 2014-10-20T18:13:54.050 に答える
-1

&何かのアドレスを返すことを意味します。*ポインタが指す変数にアクセスすることを意味します。

だから行:

pp = &entry->next;

*pp= entry->next;

異なっています。

1 つ目は のアドレスを含むポインタを設定entry->nextし、2 つ目は が指す変数の値をppと等しくなるように設定しentry->nextます。

entry->next「削除」された後に参照できるのは、リンクされたリストから削除された間、まだメモリに存在し、アクセスできるためです。

于 2014-10-20T17:52:26.157 に答える