質問には 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++ のみ、クリーンな構文でアドレスのみを渡します)。
要約すると、呼び出し元のポインターを変更する必要がある場合は、二重ポインター (またはポインターへの参照) を使用します。それ以外の場合は、ポインター (または参照) を渡すか、構造体が小さい場合は値を渡します。