5

以下のコードスニペットのメイン関数の変数iの値が、test2を介して変更されるのに、関数test1を介して変更されない理由について、誰かが説明/理由を教えてもらえますか?iの値を変更するには、1つのポインターで十分だと思います。なぜダブルポインタを使用することになっているのですか?

#include <stdio.h>

void test1(int* pp)
{
   int myVar = 9999;
   pp = &myVar;
}

void test2(int** pp)
{
   int myVar = 9999;
   *pp = &myVar;
}

int main()
{
   printf("Hej\n");
   int i=1234;
   int* p1;

   p1 = &i;

   test1(p1);
   printf("does not change..., p1=%d\n",*p1);

   test2(&p1);
   printf("changes..., p1=%d\n",*p1);
   return 0;
}
4

7 に答える 7

6

Cでは、パラメータは値で渡されます。これは、test1渡すときにポインタのコピーが作成され、それを変更すると、ポインタ自体ではなくコピーにpp変更が加えられることを意味します。コピーはダブルポインタですが、ここで逆参照して割り当てる場合test2

*pp = &myVar;

自分自身を変えるのではなく、指し示しているものを変えているのですpptest2ここにある他の回答のいくつかに記載されているように、のこの動作は未定義であることに注意してください。

于 2012-12-04T12:36:47.780 に答える
4

ただし、の値を変更するのではなく、を指すiアドレスを変更します。ppの値のみを変更する場合はi、テストを次のように変更するだけで十分です。

void test3(int* pp)
{
   int myVar = 9999;
   *pp = myVar;
}
于 2012-12-04T12:38:26.887 に答える
3

タイプの変数の値を変更する場合は、Tそのタイプのポインターを使用する必要があります(T*)。ポインタ()を変更したいので、ポインタ(T = int*)へのポインタをT* = int**指定する必要があります。そうしないと、コピーを変更するだけになります。

ご了承ください

int myVar = 9999;
*pp = &myVar;

pp関数を終了した後は無効なローカル変数のアドレスが含まれるため、未定義の動作が発生します。

于 2012-12-04T12:37:17.290 に答える
2

xがint、float、またはポインタのいずれであっても、f(x)の値は変更できないためです。x

于 2012-12-04T12:37:38.053 に答える
2
void test1(int* pp)
{
   int myVar = 9999;
   pp = &myVar;
}

この関数にはポインタが渡されますpp。この関数はそのポインターを変更します。ただし、パラメーターは値によって渡されるため、呼び出し元にはその変更は表示されません。

次のような関数を作成する必要があります。

void test1(int* pp)
{
   *pp = 9999;
}

この関数の呼び出し元は、int変数のアドレスを渡すことが期待されています。次に、関数はintそのアドレスに値(この場合は9999)を書き込みます。これが鍵です。アドレスが渡されたら、そのアドレスに値を書き込みます。壊れたバージョンは単にアドレスを変更しただけです。間接参照がありませんでした。

関数が戻ると、呼び出し元はint、アドレスが関数に渡された変数への変更を監視できます。呼び出し元のコードは次のようになります。

int i = 0;
test1(&i); // pass address of int variable
printf("%d\n", i); // prints the new value, 9999

void test2(int** pp)
{
   int myVar = 9999;
   *pp = &myVar;
}

さて、これは非常に深刻な方法で壊れています。この関数は実際に呼び出し元へのポインターを返します。ただし、関数が戻るとすぐにスコープ外になるオブジェクトへのポインタを返します。これは未定義動作として知られています。これをしないでください。関数から渡さないでください。その関数で定義されているローカル変数へのポインタです。

于 2012-12-04T12:38:58.637 に答える
1
int* p1;

   p1 = &i;

   test1(p1);  //1st

   test2(&p1);  //2nd

簡単に言えば、1番目はpass by valueで、2番目はpass by addressです。

説明 :

最初のケースでは、ポインタを渡すのは実際にはそのp内部のコピーであるtest1ため、pp内部のtest1はその関数のローカルであり、で作成されtest1ます。あなたはアドレスを割り当てました、そして、機能から出るとき、それは破壊されます。

しかし、2番目のケースでは、ポインターのアドレスを関数に渡していますtest2。したがって、のポインタppはmaintest2のポインタを指すので、 usingにp新しいアドレスを割り当てると、の値が自動的に設定されます(ポインタを逆参照しているため)。したがって、終了しても、変更された場所を指します。pp*pp = &myVarptest2p

于 2012-12-04T12:37:43.330 に答える
1

pp = &myVar;myVarのアドレスをポインタに割り当てますppppを指す値を変更する場合は、

*pp = myVar;

代わりは。

2番目の質問への回答として、既存のオブジェクトの値を変更するのではなく、ポイントされているオブジェクトを変更する場合は、ポインターをポインターに渡します。

于 2012-12-04T12:38:16.143 に答える