配列ポインタの定義
類推:
整数ポインタ-- 整数へのポインタ
int a = 10;
int* pa = &a;
文字ポインタ-- 文字へのポインタ
char ch = 'a';
char* pc = &ch;
配列ポインタ -- 配列へのポインタ
int arr[10] = { 0 };
int(*p)[10] = &arr; // 数组指针
違い: ポインタ配列と配列ポインタ
int(*p1)[10]; // 数组指针
int* p2[10]; // 指针数组
p1 は最初に * と結合され、p がサイズ 10 の整数の配列を指すポインター変数であり、すべての p1 が配列を指すポインターであり、p1 が配列ポインターであることを示します。
p2 は int* 型を格納する 10 個の要素を持つ配列であり、p2 はポインタの配列です。
注: [ ] は * よりも優先され、() を使用して p1 と * を最初に組み合わせる必要があります。
配列名と&配列名
ほとんどの場合、配列名は配列の最初の要素のアドレスですが、2 つの例外があります。
1 & 配列名、配列名は配列全体を表します
2 sizeof (配列名)、配列名は配列全体を表し、配列全体のサイズが計算されます。
int arr[10];
上記の配列の場合、arr と &arr は何を意味しますか?
arr は配列名であり、配列名は最初の要素のアドレスを表すことがわかっています。&arr が arr と同じかどうかは、まず次のコードを見てください。
int main()
{
int arr[10] = { 0 };
printf("arr = %p\n", arr);
printf("&arr= %p\n", &arr);
return 0;
}
操作結果:
&arr と arr が同じアドレスを出力していることがわかりますが、これは arr と同様に配列の最初の要素のアドレスを表すのでしょうか? 次のコードを見てください。
int main()
{
int arr[10] = { 0 };
printf("arr = %p\n", arr);
printf("&arr= %p\n", &arr);
printf("arr+1 = %p\n", arr + 1);
printf("&arr+1= %p\n", &arr + 1);
return 0;
}
操作結果:
&arr と arr は同じ値ですが、意味は異なるはずであることがわかります。実際、&arr は配列全体のアドレスを表します。この例では、&arr の型は int(*)[10] であり、配列ポインター型です。&arr+1 は配列全体のサイズを 40 オフセットし (アドレスは 16 進数で表示されます)、arr+1 は整数サイズだけオフセットします。
したがって、配列名と&配列名は値は同じでも意味は同じではなく、一方が配列の先頭要素のアドレス、もう一方が配列のアドレスであることが分かります。配列の最初のアドレスです。本質は、それらの型が異なり、1 つは同じ型のポインターであり、もう 1 つは配列ポインターであるということです。
配列ポインターと配列名の概念を理解したところで、(ポインター) 配列ポインターの型がどのようなものかを見てみましょう。
int* arr[10]; // (整型)指针数组
int* (*p)[10] = &arr; // (整型指针)数组指针
配列ポインタの使用
はじめに -- 1 次元配列へのポインタ アクセス
次のように、添字またはポインターを介して配列にアクセスできることがわかっています。
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int sz = sizeof(arr) / sizeof(arr[0]);
// 下标访问数组
for (int i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
// 指针访问数组
int* p = arr;
for (int i = 0; i < sz; i++)
{
printf("%d ", *(p + i));//*(p+i)与p[i]等价
}
return 0;
}
操作結果:
2次元配列への配列ポインタアクセス
int arr[3][3] = { 1,2,3,4,5,6,7,8,9 };
添え字を介して 2 次元配列にアクセスします。
int main()
{
int arr[3][3] = { 1,2,3,4,5,6,7,8,9 };
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
return 0;
}
操作結果:
arr[i] は実際には配列の各行の最初の要素のアドレスであり、arr[i][j] は *(arr[i]+j) と同等です。2 次元配列の場合、その最初の要素は配列の最初の行であり、その配列名は配列の最初の行のアドレス (配列ポインター) です。ポインターを使用して 1 次元配列にアクセスするのと同様に、配列ポインターを定義して 2 次元配列にアクセスできますが、これは配列ポインターの実際の用途ではありません。
配列ポインターの主な用途の 1 つは、2 次元配列をパラメーターとして受け取ることです。次に例を示します。
void print_arr(int(*arr)[3], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
}
int main()
{
int arr[3][3] = { 1,2,3,4,5,6,7,8,9 };
print_arr(arr, 3, 3);
return 0;
}
操作結果:
2 次元配列名を理解する:
実際、2 次元配列パラメータ (int arr[][3]) を渡す本質は、2 次元配列の配列名である配列ポインタを渡すことです。配列パラメータの受け渡しとポインタパラメータの受け渡しについては、次の記事で詳しく説明します。
高度なポインターの内容を学習し続けます。次の記事「配列パラメーター/ポインター パラメーター」を参照してください。