C言語で配列やデータ構造を柔軟に扱いたいと考えたとき、「多次元ポインタ」は避けて通れないテーマです。この記事では、多次元配列とポインタの違い・使い分け・実践例を中心に、初心者でも理解しやすいように解説します。
int a[1][2];
のように宣言し、メモリ上に連続した領域として確保されます。int **a;
のように宣言し、各行ごとに個別のメモリ領域を確保し、その先頭アドレスをポインタ配列で管理します。特徴 | 多次元配列 | 多次元ポインタ |
---|---|---|
メモリ配置 | 連続 | 不連続(行ごとにバラバラ) |
サイズ変更 | 不可(固定) | 可能(動的確保) |
関数渡し | 少し手間がかかる | 柔軟に渡せる |
アクセス方法 | a[i][j] | a[i][j] (同じ書き方でアクセス可能) |
int **a;
a = malloc(N * sizeof(int *));
for (int i = 0; i < N; i++) {
a[i] = malloc(M * sizeof(int));
}
このように、まず「行数分のポインタ配列」を確保し、各行ごとに「列数分の配列」を確保します。
多次元配列を動的に確保したい場合、以下のような方法が一般的です。
int **a = malloc(N * sizeof(int *));
for (int i = 0; i < N; i++) {
a[i] = malloc(M * sizeof(int));
}
この方法では、a[i][j]
で通常の多次元配列と同じ感覚でアクセスできます。
連続したメモリ領域が必要な場合は、次のように工夫することもできます。
int *data = malloc(N * M * sizeof(int));
int **a = malloc(N * sizeof(int *));
for (int i = 0; i < N; i++) {
a[i] = data + i * M;
}
こうすると、a[i][j]
も使え、かつメモリが連続します1。
int **a
のように柔軟に渡せますが、メモリ管理は自分で行う必要があります。malloc
したら必ずfree
で解放すること。ここまで紹介していましたが、はっきり言って、多次元のポインタは可読性やデータの管理等いろいろなことでトラブルのもとになりますのでお勧めはしません。
可能であれば、ポインタは1次元までで止めて、別の形で実装できるのではあれば設計するように心がけてください。
C言語の多次元ポインタの基礎から実践までを解説しました。今後も実践的なサンプルや応用テクニックを紹介していきます。