3

このコードのポインタがどのように機能するかを理解しようとしています:

void allocateArray( int **arr, size_t size, int value )
{
    *arr = malloc( size * sizeof( int ));

    if ( *arr != NULL )
        for ( size_t i = 0; i < size; ++i )
            *( *arr + i ) = value;
}

int main( void )
{
    int *vector = NULL;

    allocateArray(&vector,5,45);

    free( vector );

    return 0;
}

int ( *vector ) へのポインターを宣言した場合、そのアドレスを渡すと、int ( **arr ) へのポインターへのポインターになるのはなぜですか? つまり、メモリ内のベクトルのアドレスが上書きされるようになったので、どのように機能するのでしょうか!

4

5 に答える 5

3

C は関数パラメーターを値で渡します。したがって、関数が呼び出し元によって提供された変数を変更できるようにするには、その変数へのポインターを渡す必要があります。また、関数はポインターを逆参照して変更を行う必要があります。

void foo_1 (int a) {
    a += 1;   /* caller will not see any change to a */
}

void foo_2 (int *ap) {
    *ap += 1; /* caller will see value has changed */
}

int a = 0;
foo_1(a);  /* a is still 0 after return */
foo_2(&a); /* a becomes 1 after return */

演算子の&結果は、適用先のオブジェクトへのアドレスを表す値になり、結果の型は「(オブジェクトの型) へのポインター」になります。上記の例では、の結果&aは「へのポインタint」です。

変数がポインター型の場合、基本的に違いはありません。

void foo_1 (int *a) {
    a = malloc(sizeof(int));   /* caller will not see any change to a */
}

void foo_2 (int **ap) {
    *ap = malloc(sizeof(int)); /* caller will see value has changed */
}

int *a = 0;
foo_1(a);  /* a is still 0 after return */
foo_2(&a); /* a becomes initialized to memory allocated by malloc */

上記の例では、aは へのポインタなのでint、 の型&aは「へのポインタへのポインタint」です。


ポインターは、オブジェクトのアドレスを参照するために使用される用語です。オブジェクトのアドレスは、オブジェクトがメモリ内のどこにあるかを表す値です。そのアドレスを知ることは、オブジェクトを読み取って変更できることを意味します。ポインター変数は、オブジェクトのアドレスを格納できる変数です。

通常、変数の名前はオブジェクトを表すために使用されます。オブジェクトとは、変数によって使用されるメモリと、その意味表現、別名、その型を意味するだけです (多くの場合、変数とオブジェクトという用語は同じ意味で使用されますが、私にとっての違いは、変数には名前があることです)。オブジェクトの読み取りと変更は、名前を介して行われます。オブジェクトへのポインターを取得する 1 つの方法&は、変数の名前に単項演算子を適用することです。したがって、そのアドレスを保持するポインター変数は、そのオブジェクトへのポインターです。そして今、単項演算子を使用してポインターを逆参照することにより、その同じオブジェクトをポインターを介して読み取りおよび変更できます*

int a = 0;
int *ap = &a;
a += 1;       /* a now has the value 1 */
*ap += 1;     /* a now has the value 2 */

動的に作成されたオブジェクト、つまり を通じて作成されたオブジェクトにmalloc()は名前がありません。ただし、malloc()オブジェクトを読み取って変更できるポインターを返します。

int *ap = 0;              /* ap initialized to NULL */
ap = malloc(sizeof(int)); /* ap points to dynamically allocated int */
*ap = 0;                  /* int pointed to by ap now holds value 0 */
*ap += 1;                 /* int pointed to by ap now holds value 1 */

あなたのallocateArray()関数は、ポインタのこれらの使用の両方を 1 つの関数に結合します。

int *vector = NULL;          /* vector is pointer to int variable initialized to NULL */
allocateArray(&vector,5,45); /* the address of vector is passed to allocateArray */

vector のアドレスが に渡されるためallocateArray()、その関数は、vector受け取ったポインター値を逆参照することによって名前付きオブジェクトを変更する手段を備えています。ポインタ値はarr引数で受け取られます。

void allocateArray( int **arr, size_t size, int value )

そして、 を逆参照することにより、 によって返された値でオブジェクトをarr更新しています。vectormalloc()

*arr = malloc( size * sizeof( int ));

おそらく、メモリの割り当て、初期化、vector変数の更新が複数のステップで行われた場合、関数はより明確になるでしょう。

void allocateArray( int **arr, size_t size, int value )
{
    int *vec = malloc( size * sizeof( int ));  /* vec points to size contiguous int */

    if ( vec != NULL )
        for ( size_t i = 0; i < size; ++i )
            vec[i] = value;                    /* vec[i] set to value */

    *arr = vec;                                /* return vec into first parameter */
}
于 2013-06-14T01:04:53.120 に答える
0
int main( void )
{
    int *vector = NULL;

    allocateArray(&vector,5,45);

    free( vector );

    return 0;
}

メイン関数でわかるように、ステートメントがallocateArray(&vector,5,45);実行されると、5 要素配列のメモリ アドレスがベクトル変数に渡されます。ただし、allocateArray(vector,5,45);(修正され修正されたと仮定して) を使用すると、関数 allocateArray(vector, 5, 45) が vector の値を関数に渡しただけなので、メモリ アドレスは vector 変数に渡されません。

于 2013-06-14T03:32:13.600 に答える
0

functionmain()の中にvectorは、スタック上の単一の変数 (おそらく 4 バイト) があります。これらの 4 バイトの最初のアドレスは&vector. を呼び出すとallocateArray()、ヒープにメモリのチャンクが割り当てられます。これらのバイトのアドレスは、どこかに保存する必要があります。関数は、渡されたメモリ アドレス、つまりスタックに割り当てられたバイトにその 4 バイト アドレスを格納します。

に戻るとmain()、変数vectorは割り当てられたブロックの先頭を指しています。int へのポインタとして宣言されているため、そのメモリは int の配列としてアクセスされます。

メモリアドレスは、他の数字と同じように単なる数字です。Cで割り当てる「タイプ」は、そのアドレスのメモリで何をする予定かをコンパイラに伝えるだけです。vectorを として宣言することは、 を検出したときにメモリからint *をフェッチするようにコンパイラに指示するだけです。変数自体の値を格納するために使用されるメモリは、通常の int であるかのように単なるスタックであり、そのメモリはそれが指すメモリとは何の関係もありません。int*vector

スタック変数のアドレスを取得する必要があります。そうしないと、そのスコープで定義されていないallocateArray()variable の値に影響を与える方法がないvectorため、どこを見ればよいかを伝えるだけです。

おそらく、これを実装するより良い方法は、その最初の引数を削除してallocateArray()、割り当てられたブロックのアドレスを返すようにすることです。次に、スコープ内のvectorその戻り値に代入するだけです。main()

于 2013-06-14T01:16:54.240 に答える
0

したがって、vector は int へのポインターであるため、vector のアドレスは int へのポインターへのポインターです (&vector は int ** と同等です)。&vector = *arr ではなく、vector = *arr です。したがって、vector は、vector のアドレスではなく、malloc の呼び出しが返すアドレスを取得します。vector のアドレスと vector が指すアドレスが混同していると思います。

于 2013-06-14T01:05:16.353 に答える