[解決済み] リンクリストにノードを追加する際に、ダブルポインタを使用する理由は何ですか?
質問
以下の2つのコード例は、どちらもリンクリストの先頭にノードを追加するものです。 しかし、最初のコード例ではダブルポインタを使用しているのに対し、2番目のコード例ではシングルポインタを使用しています。
コード例 1:
struct node* push(struct node **head, int data)
{
struct node* newnode = malloc(sizeof(struct node));
newnode->data = data;
newnode->next = *head;
return newnode;
}
push(&head,1);
コード例 2:
struct node* push(struct node *head, int data)
{
struct node* newnode = malloc(sizeof(struct node));
newnode->data = data;
newnode->next = head;
return newnode;
}
push(head,1)
どちらの方法も有効です。しかし、リンクリストを使用する多くのプログラムは、新しいノードを追加するためにダブルポインタを使用します。ダブルポインタが何であるかは知っている。しかし、新しいノードを追加するにはシングルポインタで十分なのに、なぜ多くの実装がダブルポインタに依存しているのでしょうか?
シングルポインタではうまくいかないので、ダブルポインタにしなければならないケースはありますか?
どのように解決するのですか?
いくつかの実装では、ポインタへのポインタパラメータを渡すことで、新しいポインタを返す代わりに、直接ヘッドポインタを変更できるようにしています。したがって、次のように書くことができます。
// note that there's no return value: it's not needed
void push(struct node** head, int data)
{
struct node* newnode = malloc(sizeof(struct node));
newnode->data=data;
newnode->next=*head;
*head = newnode; // *head stores the newnode in the head
}
// and call like this:
push(&head,1);
headポインタを取らない実装は、新しいheadを返さなければならず、呼び出し元が自ら更新する責任があります。
struct node* push(struct node* head, int data)
{
struct node* newnode = malloc(sizeof(struct node));
newnode->data=data;
newnode->next=head;
return newnode;
}
// note the assignment of the result to the head pointer
head = push(head,1);
この関数を呼ぶときにこの代入をしないと、mallocで確保したノードをリークしてしまい、ヘッドポインタが常に同じノードを指してしまうことになります。
2つ目は、呼び出し側が返されたノードをヘッド・ポインタに代入するのを忘れると、悪いことが起こるということです。
編集する
ポインタ・トゥ・ポインタ(ダブルポインタ)は、同じプログラム内で複数のユーザー定義データ型を作成することも可能です(例:2つのリンクリストを作成する場合)。
ダブルポインタの複雑さを避けるために、常に構造体(内部ポインタとして機能する)を利用することができます。
リストは次のように定義することができます。
typedef struct list{
struct node* root;
}List;
List* create(){
List* templ=
(List*)malloc(sizeof(List));
templ->root=NULL;
return templ;
}
リンクリスト機能では、上記のリストを以下のように使用します(Push機能の例)。
void Push(List* l,int x){
struct node* n= (struct node*)malloc(sizeof(struct node));
n->data=x;
n->link=NULL;
printf("Node created with value %d\n",n->data);
if(l->root==NULL){
l->root=n;
}
else{
struct node* i=l->root;
while(i->link!=NULL){
i=i->link;
}
i->link=n;
}
}
main()関数の中で、以下のようにリストを宣言してください。
List* list1=create();
push(list1,10);
関連
-
[解決済み】エラー:cの入力の最後に期待される宣言またはステートメント
-
[解決済み】 `S_ISREG()` とは何ですか、そして何をするのですか?
-
[解決済み】「無効なイニシャライザー」と表示されるのですが、何が間違っているのでしょうか?
-
[解決済み] clang: error: linker command failed with exit code 1が表示されるのはなぜですか?
-
[解決済み】式は変更可能なL値でなければならない
-
[解決済み】MB/sとMiB/sを計算する方法は?
-
[解決済み】argv[]をint型として取得するには?
-
[解決済み】未定義参照 makefile が間違っているのかも?
-
[解決済み】シンプルなC言語のscanfが機能しない?重複
-
[解決済み] スマートポインターとは何ですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】警告:互換性のないポインタ型からの代入
-
[解決済み】 strcpyとstrdupの比較
-
[解決済み】式は変更可能なL値でなければならない
-
[解決済み】MB/sとMiB/sを計算する方法は?
-
[解決済み】コンパイラの警告 - 真理値として使用される代入の周囲に括弧を付けることを推奨する
-
[解決済み】LinuxのI_PUSHに相当するもの
-
[解決済み] テスト
-
[解決済み】エラー:呼び出されたオブジェクトは、関数または関数ポインタではない
-
[解決済み] C言語で**は何をするのですか?[重複しています]
-
[解決済み】なぜダブルインダイレクトを使うのか、なぜポインターをポインターにするのか?