多次元配列へのポインタ

C言語の多次元配列へのポインタの説明とサンプルコードです。

# 1. 配列要素へのポインタ

## 1.1. 一次元配列とポインタを組み合わせた例

``` c
#include <stdio.h>
 
#define NUMBER_OF_COLUMNS   4
 
int main(void)
{
  int linear_array_x[NUMBER_OF_COLUMNS] = {  1,  2,  3,  4};
  int linear_array_y[NUMBER_OF_COLUMNS] = { 11, 12, 13, 14};
 
  int *top_of_columns;
 
  top_of_columns = linear_array_x;
 
  printf("linear_array_x[1] = %d\n", top_of_columns[1]);  /*  2 */
 
  top_of_columns = linear_array_y;
 
  printf("linear_array_y[1] = %d\n", top_of_columns[1]);  /* 12 */
 
  return 0;
}
```

もっともシンプルな例です。整数型の１次元配列を定義して、配列の先頭要素へのアドレスをポインタ変数 int *top_of_columns に代入しています。

## 1.2. 二次元配列とポインタを組み合わせた例

最初の例では『１次元配列の先頭要素（＝整数型変数）へのポインタ』であることを強調するために１次元配列を２個用意しました。しかし、よくあるパターンは下記の例のように２次元配列を用意して、２次元配列の一部である『１次元配列の先頭要素のアドレス』をポインタ変数に代入する実装だと思います。

``` c
#include <stdio.h>
 
#define NUMBER_OF_ROWS      2
#define NUMBER_OF_COLUMNS   4
 
int main(void)
{
  int square_array[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS]
  = {
      {  1,  2,  3,  4},
      { 11, 12, 13, 14}
    };
 
  int *top_of_columns;
 
  top_of_columns = square_array[0];
 
  printf("square_array[0][1] = %d\n", top_of_columns[1]); /*  2 */
 
  top_of_columns = square_array[1];
 
  printf("square_array[1][1] = %d\n", top_of_columns[1]); /* 12 */
 
  return 0;
}
```

整数型１次元配列の先頭要素は整数型変数です。だから、その先頭要素へのポインタ変数は int *top_of_columns で辻褄が合っています。そして先頭要素から +1 オフセットした要素を参照するために上記のコードでは top_of_columns[1] という書き方をしています。 *(top_of_columns + 1) という書き方をしても同じ意味になります。

# 2. 一次元配列へのポインタ

ここからが本題です。C言語で１次元配列へのポインタをどのように記述するかを説明します。

## 2.1. 一次元配列へのポインタの例

``` c
#include <stdio.h>
 
#define NUMBER_OF_ROWS      2
#define NUMBER_OF_COLUMNS   4
 
int main(void)
{
  int square_array_x[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS]
  = {
      {  1,  2,  3,  4},
      { 11, 12, 13, 14}
    };
 
  int square_array_y[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS]
  = {
      { 21, 22, 23, 24},
      { 31, 32, 33, 34}
    };
 
  int (*top_of_rows)[NUMBER_OF_COLUMNS];
  int *top_of_columns;
 
  top_of_rows = square_array_x;
  top_of_columns = top_of_rows[1];
 
  printf("square_array_x[1][1] = %d\n", top_of_columns[1]); /* 12 */
 
  top_of_rows = square_array_y;
  top_of_columns = top_of_rows[1];
 
  printf("square_array_y[1][1] = %d\n", top_of_columns[1]); /* 32 */
 
  return 0;
}
```

１次元配列へのポインタ変数は int (*top_of_rows)[NUMBER_OF_COLUMNS] というふうに記述します。 ポインタ変数 top_of_rows はただ一つ定義されます。 「NUMBER_OF_COLUMNS個の要素をもつ１次元配列へのポインタ変数」という意味になります。

## 2.2. ポインタ配列の例

次の例にように変数定義の括弧を省略すると『配列へのポインタ』ではなく『ポインタの配列』の意味になります。

``` c
#include <stdio.h>
 
#define NUMBER_OF_ROWS      2
#define NUMBER_OF_COLUMNS   4
 
int main(void)
{
  int square_array[NUMBER_OF_ROWS][NUMBER_OF_COLUMNS]
  = {
      {  1,  2,  3,  4},
      { 11, 12, 13, 14}
    };
 
  int *top_of_columns[NUMBER_OF_ROWS];
 
  top_of_columns[0] = square_array[0];
  top_of_columns[1] = square_array[1];
 
  printf("square_array[0][1] = %d\n", top_of_columns[0][1]); /*  2 */
 
  printf("square_array[1][1] = %d\n", top_of_columns[1][1]); /* 12 */
 
  return 0;
}
```

int top_of_columns[0] と int top_of_columns[1] の２つのポインタ変数が配列として定義されています。そして上記の例では、２つのポインタ変数にたまたま『異なる２つの変数（配列の先頭要素）のアドレス』を代入しています。複数のポインタ変数が異なる変数を指し示していても、たった一つの変数を指し示していても構いません。上記のサンプルコードはシンプルな内容を持って回った書き方をしているため、ポインタ変数配列を使用する旨味はありませんが、ポインタ変数の使い方次第です。

## 2.3. 三次元配列と一次元配列へのポインタを組み合わせた例

``` c
#include <stdio.h>
 
#define NUMBER_OF_PAGES     2
#define NUMBER_OF_ROWS      3
#define NUMBER_OF_COLUMNS   4
 
int main(void)
{
  int cubic_array[NUMBER_OF_PAGES][NUMBER_OF_ROWS][NUMBER_OF_COLUMNS]
  = {
      {
        {  1,  2,  3,  4},
        { 11, 12, 13, 14},
        { 21, 22, 23, 24},
      },
      {
        {101,102,103,104},
        {111,112,113,114},
        {121,122,123,124},
      },
    };
 
 
  int (*top_of_rows)[NUMBER_OF_COLUMNS];
  int *top_of_columns;
 
  top_of_rows = cubic_array[0];
  top_of_columns = top_of_rows[1];
 
  printf("square_array[0][1][1] = %d\n", top_of_columns[1]); /* 12 */
 
  top_of_rows = cubic_array[1];
  top_of_columns = top_of_rows[1];
 
  printf("square_array[1][1][1] = %d\n", top_of_columns[1]); /*112 */
 
  return 0;
}
```

ここまで複雑になると何がなんやらですが、上記の例では３次元配列を使い２次元配列を２個定義しています。そして２次元配列の先頭要素（＝１次元配列へのポインタ）を top_of_rows に代入しています。　top_of_rows も top_of_columns も１個しかため異なる配列要素を参照するために値の上書きをおこなっています。

# 3.  二次元配列へのポインタ

下記が３次元配列を２個定義して、２次元配列へのポインタに代入する例です。

``` c
#include <stdio.h>
 
#define NUMBER_OF_PAGES     2
#define NUMBER_OF_ROWS      3
#define NUMBER_OF_COLUMNS   4
 
int main(void)
{
  int cubic_array_x[NUMBER_OF_PAGES][NUMBER_OF_ROWS][NUMBER_OF_COLUMNS]
  = {
      {
        {  1,  2,  3,  4},
        {  5,  6,  7,  8},
        {  9, 10, 11, 12},
      },
      {
        { 13, 14, 15, 16},
        { 17, 18, 19, 20},
        { 21, 22, 23, 24},
      }
    };
 
  int cubic_array_y[NUMBER_OF_PAGES][NUMBER_OF_ROWS][NUMBER_OF_COLUMNS]
  = {
      {
        {101,102,103,104},
        {105,106,107,108},
        {109,110,111,112},
      },
      {
        {113,114,115,116},
        {117,118,119,120},
        {121,122,123,124},
      }
    };
 
  int ((*top_of_array)[NUMBER_OF_ROWS])[NUMBER_OF_COLUMNS];
  int (*top_of_page)[NUMBER_OF_COLUMNS];
  int *top_of_row;
 
  top_of_array = cubic_array_x;
  top_of_page  = top_of_array[1];
  top_of_row   = top_of_page[1];
 
  printf("array_x[1][1][1] = %d\n", top_of_row[1]);
 
  top_of_array = cubic_array_y;
 
  printf("array_y[1][1][1] = %d\n", top_of_array[1][1][1]);
 
  return 0;
}
```

int ((*top_of_array)[NUMBER_OF_ROWS])[NUMBER_OF_COLUMNS] と記述することで２次元配列へのポインタを定義することができます。括弧の位置が重要です。括弧を省略してしまうと『配列へのポインタ』ではなく『ポインタの配列』になります。４次元配列を定義して２次元配列へのポインタに代入することもできますが、配列定義が煩雑になるためサンプルコードは省きます。

以上、『配列へのポインタ』の説明でした。