1

私は最近、リンクされたリストとツリーに取り組んでいます。しかし、関数を次のように宣言するタイミングがわかりません。

preorder(struct node* root); 
or
preorder(struct node** root);

両方がまったく同じように機能する場合。より正確に言うと、関数をダブル ポインターとシングル ポインターとして設計する必要があるのはいつですか。

ありがとう。

PS: リンク リストにノードを挿入するには、次のようにダブル ポインターが必要です。

insert(struct node** root,int value);

ルート ノードがグローバル値として定義されている場合を除きます。予約注文は単一のポインターでうまく機能しますが。誰かがこれを例として説明できれば、非常に役に立ちます。

4

5 に答える 5

1

ルーチンに渡されるものを変更したい場合は、代わりにポインターを渡します。物事はポインターでもあるため、混乱が生じます。

したがって、ポインターをルーチンに渡したい場合、および (潜在的に) ポインター自体を変更したい場合は、二重ポインターを使用します。

ルーチンにポインターを渡したいが、ポインターが指している対象を変更または照会するだけの場合は、単一のポインターを使用します。

それが違いです。ポインターを変更しますか、それともポインターが指しているものにアクセスしますか。

于 2013-09-29T07:56:43.630 に答える
0

質問には C と C++ の両方のタグが付けられているため、その観点から違いを見てみましょう。この回答は、通常C++ コードで優先されるC++ コンテナー クラスまたはスマート ポインターには触れていません。以下に 4 つのケースを示します。2 つは呼び出し元の構造体と呼び出し元のポインターを変更できるケースで、2 つは特定の構造体の内容のみを変更できるケースです。

C++ 変更ポインター

関数でポインターを変更し、ポインター値を C++ の呼び出し元に返すようにする場合は、ポインターへの参照を使用してこれを行います。

void clearNode(struct node *&n){
    n->field = 0; // modify caller's struct
    n = nullptr; // set caller's pointer to NULL (C++11)
}
...
struct node n; // value
struct node *np = &n; // pointer to node
clearNode(np); // OK, np becomes null, n.field becomes 0
clearNode(&np); // will not compile, &np is not right type
clearNode(&n); // will not compile, &n is not lvalue

C 変更ポインター

C では、同じコードは次のようになります (C++ でも機能しますが、上記のバージョンの方が優れていてクリーンです)。

void clearNode(struct node **n){
    (*n)->field = 0; // modify caller's struct
    *n = NULL; // set caller's pointer to NULL
}
...
struct node n; // value
struct node *np = &n; // pointer to node
clearNode(np); // will not compile, np is not right type
clearNode(&np); // OK, np becomes NULL, n.field becomes 0
clearNode(&n); // will not compile, &n is not of right type

C 変更のみ構造体

しかし、ポインタだけで同じコードを書くと、動作が少し異なります。

void clearNode(struct node *n){
    n->field = 0; // modify caller's struct
    n = NULL; // change local parameter, which in this case has no effect anywhere
}
...
struct node n; // value
struct node *np = &n; // pointer to node
clearNode(np); // OK, except np is not modified, n.field becomes NULL
clearNode(&np); // will not compile, &np is not of right type
clearNode(&n); // OK, n.field becomes NULL

C++ 変更のみの構造体

そして最後に、C++ の同じコードは次のようにするとよりきれいになります。

void clearNode(struct node &n){
    n.field = 0; // modify caller's struct
    // no pointer, nothing to set to NULL
}
...
struct node n; // value
struct node *np = &n; // pointer to node
clearNode(np); // will not compile, np is not of right type
clearNode(&np); // will not compile, &np is not of right type
clearNode(&n); // will not compile, &n is not of right type
// these work, n.field becomes 0:
clearnode(n);
clearnode(*np);

あなたの質問

したがって、上記から取るべきことは、呼び出し元のポインターを変更する必要がある場合は、ポインターをポインターに渡す (C および C++) か、参照をポインターに渡す (C++) ことです。これにはコストがかかります。変更可能なポインター変数を常に渡す必要があり、二重間接参照のオーバーヘッドもわずかです。両方の構文を上に示します。

呼び出し元のポインターを変更する必要はないが、構造体の内容を変更する必要がある場合は、ポインター (C および C++) または参照 (C++) を構造体に渡します。両方の構文を上に示します。

何も変更する必要がない 3 番目のケースは、上記ではカバーされていませんが、3 つの基本的な代替手段があります。少し醜い構文ですが、アドレスだけを渡します) または const 参照で渡します (C++ のみ、クリーンな構文でアドレスのみを渡します)。

要約すると、呼び出し元のポインターを変更する必要がある場合は、二重ポインター (またはポインターへの参照) を使用します。それ以外の場合は、ポインター (または参照) を渡すか、構造体が小さい場合は値を渡します。

于 2013-09-29T15:34:39.953 に答える