C言語のconstとポインタ

C言語のconstとポインタはややこしい。

まずは普通の変数の宣言と代入です。

int8_t test1 = 0;
test1 = 1;

これは普通のint8_tの変数を宣言し、
その後に1を代入しています。

次に、

int8_t* test2 = &test1;
*test2 = 1;

これも普通のint8_tのポインタです。
test2にはtest1のアドレスを格納しているので、
*test2への代入はtest1への代入ということになります。

次は、

int8_t** test3 = &test2;
**test3 = 1;

これはポインタのポインタです。
test3にはtest2のポインタを格納しているので、
**test3への代入は*test2への代入、すなわちtest1への代入と同じことになります。

つまり、上記は3つとも、test1 = 1 という処理になります。

ここからはconstの登場です。

const int8_t test4 = 0;

これは定数としての宣言となります。test4の値は0となり、新たに値を代入しようとするとコンパイルエラーとなります。

次はポインタです。

const int8_t* test5 = &test1;

この場合、ポインタの指す先が定数ということになるため、*test5 = 1のようにしてtest1の値を書き換えることはできません。
test5 = &test4のように、test5の値を変更することはできます。

一方、次のような場合、

int8_t* const test6 = &test1;

*test6 = 1のようにしてtest1の値を書き換えることはできますが、test6 = NULLといったようにtest6の値を変更することができなくなります。

そして、下記のようにすると

const int8_t* const test7 = &test1;

*test7 = 1やtest7 = NULLなどどちらもできなくなります。

ややこしいです。さらにダブルポインタにしてみると余計にややこしくなります。

int8_t test8 = 0;
int8_t* test9 = &test8;

int8_t** test10 = &test9;
int8_t** const test11 = &test9;
int8_t* const* test12 = &test9;
int8_t* const* const test13 = &test9;
const int8_t** test14 = (const int8_t**)&test9;
const int8_t** const test15 = (const int8_t**)&test9;
const int8_t* const* test16 = &test9;
const int8_t* const* const test17 = &test9;

test10は普通のダブルポインタの変数なので、
test10 = NULLや*test10 = NULL、**test10 = 1などいずれも可能です。

test11はtest11 = NULLがエラーとなりますが、*test11 = NULLや**test11 = 1は可能です。

以降も同じようにして、次のような結果となります。
test12 = NULL 可能
*test12 = NULL エラー
**test12 = 1 可能

test13 = NULL エラー
*test13 = NULL エラー
**test13 = 1 可能

test14 = NULL 可能
*test14 = NULL 可能
**test14 = 1 エラー

test15 = NULL エラー
*test15 = NULL 可能
**test15 = 1 エラー

test16 = NULL 可能
*test16 = NULL エラー
**test16 = 1 エラー

test17 = NULL エラー
*test17 = NULL エラー
**test17 = 1 エラー

スポンサーリンク