C言語にはconst修飾子というものがありますが,ポインタの宣言でこれを用いる場合,「ポインタの型/間接演算子(*)/const修飾子」の書く位置によって,意味が異なってきます.知っている人にとっては常識なのかもしれませんが,私はこれに関して曖昧だったので,復習も兼ねてまとめてみます.
constを*よりも前に書いた場合,ポインタが指している実体が固定になります.このとき,intとconstの順番は関係ありません.一方,constを*の後に書いた場合は,そのポインタ自体が固定になります.
const int * cipHoge = &hoge; // ポインタの先の実体を固定
int const * icpHoge = &hoge; // ポインタの先の実体を固定
int * const ipcHoge = &hoge; // ポインタ自身を固定
*cipHoge = piyo; // error
*icpHoge = piyo; // error
*ipcHoge = piyo;
cipHoge = &piyo;
icpHoge = &piyo;
ipcHoge = &piyo; // error
また,実体とポインタの両方を固定したい場合,*の前後にconstをつければよいことになります.
const int * const cipcHoge = &hoge;
int const * const icpcHoge = &hoge;
つぎに,*が2つの場合です.constを二つの*よりも前に書いた場合,ポインタの先の先にある実体が固定になります.constを二つの*の間に書いた場合,そのポインタが指すポインタが固定されます.constを二つの*の後に書いた場合,そのポインタ自身が固定になります.
typedef const int * * CIPP;
typedef int const * * ICPP;
typedef int * const * IPCP;
typedef int * * const IPPC;
CIPP cippHoge = (CIPP)&pHoge; // ポインタの先の先の実体を固定
ICPP icppHoge = (ICPP)&pHoge; // ポインタの先の先の実体を固定
IPCP ipcpHoge = (IPCP)&pHoge; // ポインタの先のポインタを固定
IPPC ippcHoge = (IPPC)&pHoge; // ポインタ自身を固定
**cippHoge = fuga; // error
**icppHoge = fuga; // error
**ipcpHoge = fuga;
**ippcHoge = fuga;
*cippHoge = pFuga;
*icppHoge = pFuga;
*ipcpHoge = pFuga; // error
*ippcHoge = pFuga;
cippHoge = (CIPP)&pFuga;
icppHoge = (ICPP)&pFuga;
ipcpHoge = (IPCP)&pFuga;
ippcHoge = (IPPC)&pFuga; // error
もちろん,これらを組み合わせて使うこともできます.