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
更新しています。vector
malloc()
*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 */
}