多次元の配列へのポインタ配列の型

C言語はポインタ変数の型を考えるのが大変。 先日、多次元配列へのポインタ配列を返す関数の宣言が思い浮かばなかったので、復習する事にした。

前提として、 扱うデータは、以下の多次元配列が複数個とする。

char a[2][3] = {{10,11,12},{13,14,15}};
char b[2][3] = {{20,21,22},{23,24,25}};
char c[2][3] = {{30,31,32},{33,34,35}};
char d[2][3] = {{40,41,42},{43,44,45}};

まず、配列のポインタ。これはいいよね。

char (*p)[2][3] = &a;
printf("%d\n", (*p)[1][2]); // => 15

次は、配列のポインタの配列。 早くもつまづきそうになるが、ポインタ宣言は右優先で考えていけばいいので

char (*q[4])[2][3] = { &a, &b, &c, &d };
printf("%d\n", (*q[1])[1][2]); // => 25

配列のポインタの配列のポインタ。 日本語としても意味が分かりづらいが、1つ前の例との差分を考えていけばコードが書ける。

char (*(*r)[4])[2][3] = &q;
printf("%d\n", (*(*r)[2])[1][2]); // => 35

このように、順にコードを書いてけば、 配列のポインタの配列のポインタを返却する関数も宣言できるようになる。

まずは、考えるのが面倒で void* に頼ってしまうダメな例を先に。

void *f(void){
  static char (*p[4])[2][3] = { &a, &b, &c, &d };
  return (void*)&p;
}

これを、ポインタ変数の宣言ができればこうなる。

char (*(*f(void))[4])[2][3]{
  static char (*p[4])[2][3] = { &a, &b, &c, &d };
  return &p;
}

printf("%d\n", (*(*(*f)())[3])[1][2]); // => 45

ふぅ、満足。