logo

C ダブルポインタ(ポインタツーポインタ)

ご存知のとおり、C では変数のアドレスを格納するためにポインターが使用されます。ポインターを使用すると、変数のアクセス時間が短縮されます。ただし、C では、別のポインターのアドレスを格納するポインターを定義することもできます。このようなポインタはダブル ポインタ (ポインタツーポインタ) として知られています。最初のポインタは変数のアドレスを格納するために使用され、2 番目のポインタは最初のポインタのアドレスを格納するために使用されます。以下の図で理解してみましょう。

C のポインタへのポインタ

ダブルポインタを宣言する構文を以下に示します。

 int **p; // pointer to a pointer which is pointing to an integer. 

次の例を考えてみましょう。

 #include void main () { int a = 10; int *p; int **pp; p = &a; // pointer p is pointing to the address of a pp = &p; // pointer pp is a double pointer pointing to the address of pointer p printf('address of a: %x
',p); // Address of a will be printed printf('address of p: %x
',pp); // Address of p will be printed printf('value stored at p: %d
',*p); // value stoted at the address contained by p i.e. 10 will be printed printf('value stored at pp: %d
',**pp); // value stored at the address contained by the pointer stoyred at pp } 

出力

 address of a: d26a8734 address of p: d26a8738 value stored at p: 10 value stored at pp: 10 

Cのダブルポインタの例

1 つのポインターが別のポインターのアドレスを指す例を見てみましょう。

for ループ Java の拡張
C ポインタからポインタの例

上の図からわかるように、p2 には p のアドレス (fff2) が含まれ、p には数値変数のアドレス (fff4) が含まれます。

DSにスタックする
 #include int main(){ int number=50; int *p;//pointer to int int **p2;//pointer to pointer p=&number;//stores the address of number variable p2=&p; printf('Address of number variable is %x 
',&number); printf('Address of p variable is %x 
',p); printf('Value of *p variable is %d 
',*p); printf('Address of p2 variable is %x 
',p2); printf('Value of **p2 variable is %d 
',*p); return 0; } 

出力

 Address of number variable is fff4 Address of p variable is fff4 Value of *p variable is 50 Address of p2 variable is fff2 Value of **p variable is 50 

Q. 次のプログラムの出力は何ですか?

 #include void main () { int a[10] = {100, 206, 300, 409, 509, 601}; //Line 1 int *p[] = {a, a+1, a+2, a+3, a+4, a+5}; //Line 2 int **pp = p; //Line 3 pp++; // Line 4 printf('%d %d %d
',pp-p,*pp - a,**pp); // Line 5 *pp++; // Line 6 printf('%d %d %d
',pp-p,*pp - a,**pp); // Line 7 ++*pp; // Line 8 printf('%d %d %d
',pp-p,*pp - a,**pp); // Line 9 ++**pp; // Line 10 printf('%d %d %d
',pp-p,*pp - a,**pp); // Line 11 } 

説明

ダブルポインターの質問

上記の質問では、ダブル ポインターを使用してポインター演算が使用されています。ポインター p の配列によってポイントされる 6 つの要素の配列が定義されます。ポインタ配列 p は、ダブル ポインタ pp によってポイントされています。ただし、上の図は、メモリが配列 a とポインタ配列 p にどのように割り当てられるかを簡単に示しています。 p の要素は、配列 a のすべての要素を指すポインターです。配列名には配列のベース アドレスが含まれていることがわかっているため、ポインターとして機能し、*(a)、*(a+1) などを使用して値をトラバースできます。 、a[0] には次の方法でアクセスできます。

  • a[0]: 配列の最初の要素にアクセスする最も簡単な方法です。
  • *(a): a には配列の最初の要素のアドレスが格納されるため、間接ポインタを使用してその値にアクセスできます。
  • *p[0]: ポインタ p を使用して a[0] にアクセスする場合、ポインタ配列 p の最初の要素、つまり *p[0] に間接演算子 (*) を使用できます。
  • **(pp): pp はポインタ配列のベース アドレスを格納するため、*pp は整数配列の最初の要素のアドレスであるポインタ配列の最初の要素の値を与えます。 **p は、整数配列の最初の要素の実際の値を示します。

プログラムの 1 行目と 2 行目では、整数とポインタ配列を相対的に宣言しています。 3 行目では、ポインタ配列 p への double ポインタを初期化します。画像に示すように、配列のアドレスが 200 から始まり、整数のサイズが 2 の場合、ポインター配列には 200、202、204、206、208、210 の値が含まれます。ポインタ配列のベースアドレスは 300 です。ダブル ポインタ pp には、ポインタ配列のアドレス、つまり 300 が含まれています。行番号 4 では、pp の値が 1 ずつ増加します。つまり、pp はアドレス 302 を指すようになります。

行番号 5 には、3 つの値、つまり pp - p、*pp - a、**pp を出力する式が含まれています。それぞれを計算してみましょう。

  • pp = 302、p = 300 => pp-p = (302-300)/2 => pp-p = 1、つまり 1 が出力されます。
  • pp = 302, *pp = 202, a = 200 => *pp - a = 202 - 200 = 2/2 = 1、つまり 1 が出力されます。
  • pp = 302、*pp = 202、*(*pp) = 206、つまり 206 が印刷されます。

したがって、5 行目の結果として、出力 1、1、206 がコンソールに表示されます。 6行目に*pp++と書いてあります。ここで、2 つの単項演算子 * と ++ が同じ優先順位を持つことに注意する必要があります。したがって、結合性の法則により、右から左に評価されます。したがって、式 *pp++ は (*(pp++)) として書き換えることができます。 pp = 302 なので、304 になります。 *pp は 204 になります。

Mavenリポジトリ

7 行目にも、3 つの値、つまり pp-p、*pp-a、*pp を出力する式が書かれています。それぞれを計算してみましょう。

  • pp = 304、p = 300 => pp - p = (304 - 300)/2 => pp-p = 2、つまり 2 が出力されます。
  • pp = 304, *pp = 204, a = 200 => *pp-a = (204 - 200)/2 = 2、つまり 2 が出力されます。
  • pp = 304、*pp = 204、*(*pp) = 300、つまり 300 が印刷されます。

したがって、7 行目の結果として、出力 2、2、300 がコンソールに表示されます。 8行目には++*ppと書かれています。結合性の法則によれば、これは (++(*(pp))) と書き直すことができます。 pp = 304、*pp = 204 なので、*pp = *(p[2]) = 206 の値は a[3] を指すことになります。

9 行目では、3 つの値、つまり pp-p、*pp-a、*pp を出力する式が再び書かれています。それぞれを計算してみましょう。

  • pp = 304、p = 300 => pp - p = (304 - 300)/2 => pp-p = 2、つまり 2 が出力されます。
  • pp = 304, *pp = 206, a = 200 => *pp-a = (206 - 200)/2 = 3、つまり 3 が出力されます。
  • pp = 304、*pp = 206、*(*pp) = 409、つまり 409 が印刷されます。

したがって、9 行目の結果として、出力 2、3、409 がコンソールに表示されます。 10行目には++**ppと書かれています。結合性の法則に従って、これは (++(*(*(pp)))) のように書き直すことができます。 pp = 304、*pp = 206、**pp = 409、++**pp => *pp = *pp + 1 = 410。つまり、a[3] = 410。

ハードカバーとペーパーバック

11 行目では、3 つの値、つまり pp-p、*pp-a、*pp を出力する式が再び書かれています。それぞれを計算してみましょう。

  • pp = 304、p = 300 => pp - p = (304 - 300)/2 => pp-p = 2、つまり 2 が出力されます。
  • pp = 304, *pp = 206, a = 200 => *pp-a = (206 - 200)/2 = 3、つまり 3 が出力されます。
  • 8 行目、**pp = 410。

したがって、9 行目の結果として、出力 2、3、410 がコンソールに表示されます。

最終的に、完全なプログラムの出力は次のようになります。

出力

 1 1 206 2 2 300 2 3 409 2 3 410