1

私はこのページから学びました:FAQ関数内でポインターを初期化したい場合は、ポインターをポインターに渡す必要があります**pfoo1()

void foo1(int **p) {
    *p = malloc(100*sizeof(int)); // caller can get the memory
}

void foo2(int *p) {
    p = malloc(100*sizeof(int));  // caller cannot get the memory
}

ただし、ポインターは、その値が指すアドレスであることを意味します。foo2()スコープを離れた後、割り当てられたメモリはどこに行きますか?

ポインターを値に渡す場合とポインターをポインターに渡す場合の動作の違いをまだ理解できませんか? SOを検索しましたが、解決策または簡単な説明しか見つかりませんでした。誰かがより詳細に助けることができますか?

4

7 に答える 7

5

に割り当てられたメモリfoo2が失われます。これにより、リターン後に割り当てられたメモリをどこで見つけて使用するかわからないため、メモリリークが発生foo2します。

検討:

int *mymemory = NULL;
foo2(mymemory);
//mymemory is still NULL here. Memory has been allocated, 
//but you don't know at which address
//in particular, you will never be able to free() it

対:

int *mymemory = NULL;
foo1(&mymemory);
//mymemory is now the address of the memory
//allocated by the function
dostuffwith(mymemory);
free(mymemory);
于 2013-09-13T09:19:47.650 に答える
2

2番目の例では、割り当てられたメモリがリークされています.foo2が終了すると、割り当てられたアドレスを含む変数が残っていないため、解放できません。

検討することもできます

void foo3 (int bar) {
    bar = 8;
}

int main (int argc, char *argv[]) {
    int x = 0;
    foo3(x);
    printf("%d\n", x);
    return 0;
}

foo3 が終了しても、x は 0 のままです - foo3 の bar の内容の変更は、渡された外部変数には影響しません。単一のポインターを渡すときとまったく同じことをしています。一部のメモリのアドレスにアクセスしますが、関数が終了するとそのアドレスが失われます。

于 2013-09-13T09:20:31.573 に答える
1

値へのポインターの受け渡し: ポインターのコピー (つまり、値のアドレス) が関数内 (上) で作成されますstack frame。これにより、値を変更できます。

ポインターへのポインターの受け渡し: ポインターへのポインターのコピー (つまり、値を指すポインターのアドレス) が関数で (上でstack frame) 作成されます。これにより、値とこの値へのポインターを変更できます。

malloccallocreallocおよびを使用して割り当てられたメモリは、関数が返された (new破棄された)heap後でも存在することを意味しますstack frame

void foo2(int *p) {
    p = (int *) malloc(100);  // caller cannot get the memory
}

ただし、関数が返されるとポインタpが失われるため、このメモリにアクセスできず、リークが発生します。

于 2013-09-13T09:31:15.807 に答える
1

問題foo2は、渡された が関数p内でのみ変更されることです。foo2これは次と同じです:

void bar(int x)
{
   x = 42;
}

... 
    int a = 7;
    bar(a);
...

上記のコードでaは、 への呼び出しのため、 は変更されませんbar。代わりに、 のコピーaが に渡されbar、そのコピーが で変更されbarます。

でまったく同じことが起こりfoo2ます。メモリが割り当てられ、p渡されたポインタのコピーである に格納されます。コードが戻ると、元のポインタは元の値を保持します。

ポインター ( &ptr)のアドレスを に渡すfoo1ことで、ORIGINAL ポインターを変更できるため、割り当てのアドレスを の呼び出し元に戻すことができfoo1ます。

もちろん、 を呼び出した後のように、最初に割り当てられたメモリへの参照がない場合foo2、これはメモリ リークと呼ばれ、一般に悪いことと見なされます。

于 2013-09-13T09:24:34.277 に答える
0

すべての引数の動作はローカル変数と同じ (値渡し) であるため、値渡しのポインターを変更することはできません。

そのため、foo2()メモリを割り当てますが、実際にローカル変数を変更するため、関数の外では使用できません。

foo()関数は が指す値を実際に変更するため、**p関数に渡されるポインタは更新されます。

于 2013-09-13T09:24:13.487 に答える