最近の書込みリストでは、研究の過程で最終的に意味や関数のパラメータにダブルポインタの使用の使用を理解し、ポインタについての質問に来たとき。
私たちは、機能を書くことについて話し始めます。この関数は、リンクリストの先頭にノードを挿入する必要があり、このリストは最初のノードではなく、必要と戻り値がvoidです。これは、リストの先頭ポインタの変更を完了させる機能です。
私の文章の始まりはこれです:
typedef struct ListNode{
int val;
struct ListNode* next;
}ListNode;
void myLinkedListAddAtHead(ListNode* obj,int val){
ListNode *List=obj;
ListNode *Temp=malloc(sizeof(ListNode));
if(temp==NULL){
prinf("Out of space!");
}
else{
Temp->val=val;
Temp->next=List;
obj=Temp;
}
}
読者は、この機能が問題であると考えるために始めることができます。別の簡単な例を見て、のはさておき例を脇に置くましょう。今設計するために、スイッチング機能は、B値。
最初の二つの変数の直接伝送パラメータによって書かれた、印刷中の親機能に交換しました。
void Swap(int a,int b)
{
int tmp = a;
a = b;
b = tmp;
}
int main()
{
int a=1;
int b=2;
printf("a=%d,b=%d\n",a,b);
Swap(a,b);
printf("a=%d,b=%d\n",a,b);
return 0;
}
出力は次のようになります。
1,2
2,1
結果は成功の交換ではありません。私たちは、何が悪かったのか、メモリの割り当てと変数の交換の1を見てください。
黒と赤の変数、Bのこの写真は、同じ名前が、それがあることに留意されたい二つの異なるメモリ空間。関数が値を返さないので、私たちはただ、Bの赤の値の内部機能を変更し、主な機能ブラック、Bの値は変更されません。したがって、Bのメイン関数値に印刷し、変化しない場合。
我々は成功したいのであれば、出力は、出力は関数の内部で行われます。
void Swap(int a,int b)
{
int tmp = a;
a = b;
b = tmp;
printf("a=%d,b=%d\n",a,b);//在函数中输出
}
int main()
{
int a=1;
int b=2;
printf("a=%d,b=%d\n",a,b);
Swap(a,b);
return 0;
}
出力は次のようになります。
1,2
2,1
結果は成功した交換です。もちろん、黒、Bの変数は、まだ我々はちょうど交換後の変数の赤の値を印刷し、交換します。
だから我々はそれを行う方法を、bの値を交換したいですか?私たちは自然に二つの記憶が無いの成功が得られちょうど黒と赤のしていると思うので、我々は同じメモリ空間にそれらを聞かせては、まだラインではないのですか?そこで、第2のアプローチは、関数に渡された変数に対処することです。
void Swap(int *p1,int *p2)
{
int *tmp = p1;
p1 = p2;
p2 = tmp;
}
int main()
{
int a=1;
int b=2;
printf("a=%d,b=%d\n",a,b);
Swap(&a,&b);
printf("a=%d,b=%d\n",a,b);
return 0;
}
出力は次のようになります。
1,2
1,2
かではありません。これはなぜでしょうか?のは、メモリ割り当てのケースを分析してみましょう。
私たちは、もともと対処するために導入されたが、内部関数は、単に変数のアドレスポインタを交換しますが、A、Bの値が変更されないまま。だから我々は、交換する必要があるポインタが、アドレス(* p1と* p2の)での値へのポインタではありません。
void Swap(int *p1,int *p2)
{
int *tmp;
*tmp = *p1;
*p1 = *p2;
*p2 = *tmp;
}
int main()
{
int a=1;
int b=2;
printf("a=%d,b=%d\n",a,b);
Swap(&a,&b);
printf("a=%d,b=%d\n",a,b);
return 0;
}
動作中のプログラムがクラッシュしました。オリジナルtmpが野生ポインタで、INT * TMPは、コンピュータシステムに格納されたランダムなアドレス値です。直接変更は予測できないエラーが発生します。だから我々は直接代わりに、以下に示すようなTMP *のint型のTMPの変数を使用します。
void Swap(int *p1,int *p2)
{
int tmp;
tmp = *p1;
*p1 = *p2;
*p2 = tmp;
}
int main()
{
int a=1;
int b=2;
printf("a=%d,b=%d\n",a,b);
Swap(&a,&b);
printf("a=%d,b=%d\n",a,b);
return 0;
}
私たちは、元の質問に戻りましょう、堂々巡りした後、あなたはまだ問題を発見しますか?はい、objパラメータに赤の変数に書かれた最初のと等価である、彼は元のリストの最初のノードへのポインタポイントのコピーを保存しました。つまり、この空間にリストの先頭のアドレスをコピーし、内部関数ポインタのサイズのためのスペースを開きました。元の関数の内部空間の操作は、リストの先頭から完全に独立しています。
したがって、前述の例では慣例に従って、我々はここでビューのintとしてListNode *を持っている、あなたは私たちが、すなわちListNode ListNodeの*アドレスを渡す必要があることがわかります**。これは、我々は、ポインタのアドレスを変更したい、ダブルポインタの原点です。私たちの最終的な文言は次のようになります。
typedef struct ListNode{
int val;
struct ListNode* next;
}ListNode;
void myLinkedListAddAtHead(ListNode** obj,int val){
ListNode *List=*obj;//obj存储的是指向链表第一个节点的指针的地址,List存储obj地址中保存的值,即链表第一个节点的地址
ListNode *Temp=malloc(sizeof(ListNode));
if(temp==NULL){
prinf("Out of space!");
}
else{
Temp->val=val;
Temp->next=List;
*obj=Temp;//将新节点的地址赋值给obj指向的地址,即赋值给指向链表第一个节点的指针
}
}
巻線が地図上、まだ非常に言葉で言いました:
最後に行われ、今、私たちは最終的に二重のポインタの役割を理解しています。しかし、ポインタを返すことが許可されている場合、実際には、物事がより簡単だったかもしれない、我々はまた、二重のポインタを使用しないでください。