色々な言語で配列の最後の要素を取り出すという記事のコメントで、 C では *((&x)[1]-1)
という式で可能だという提案をしました。
この式は技巧的なので日常的に使う定型句としては適さないと思うのですが、初心者がしばしば引っかかりがちな考え方を含むので逆に題材としては面白いのではないかと考え、型を中心に解説を試みます。
変数 x
が要素数 N
で型 T
の配列であるとき、つまり x
が
T x[N];
と宣言されているとき、 *((&x)[1]-1)
という式の各段階の型はこうなります。
式 | 型 | 備考 |
---|---|---|
x |
T[N] |
- |
&x |
T(*)[N] |
配列を指すポインタ |
(&x)[1] |
T[N] |
ただし、暗黙の型変換で T* に読み替えられる |
(&x)[1]-1 |
T* |
- |
*((&x)[1]-1) |
T |
- |
最終的に返ってくる値の型は、配列の要素の型となります。
このとき、重要な点として
- 配列は (いくつかの例外を除いて) 暗黙の型変換で配列の先頭要素を指すポインタになる
- 配列の先頭要素を指すポインタとは別に配列を指すポインタが存在する
- 配列にアドレス演算子 (
&
) を適用したときは暗黙の型変換の例外となり、配列の先頭要素ではなく配列を指すポインタとなる
を意識してください。
ポインタに対して [1]
と付けたときには、指している先の次の要素を取り出すことはわかると思いますが、指している先が配列であれば次の配列を指し、更にその配列の先頭要素を指すポインタに暗黙に型変換されるため、結果的に (&x)[1]
は配列 x
の最後の要素の次を指すポインタです。 そこから 1 を減算することで配列の最後を指すポインタになるわけです。
一見してわかり難い式も規則に基づいて型を意識することで意味を理解しやすくなります。