const修飾子を変数宣言で型の前に付けると、値が変更できない変数(つまり定数)となる・・・。
const <型> <変数名>
例えば、
/* ヘッダファイルのインクルード */ #include <stdio.h> /* 標準入出力 */ /* main関数の定義 */ int main(void){ /* 変数の初期化 */ int a = 10; /* aを10に初期化. */ const int b = 100; /* bは100とする.(constが付いているので定数として扱われる. */ /* 値の出力 */ printf("a = %d\n", a); /* aの値を出力. */ printf("b = %d\n", b); /* bの値を出力. */ /* プログラムの終了 */ return 0; }
aを10, bを100に初期化しておいてbをconstにする・・・。
$ gcc const.c -o const $ ./const a = 10 b = 100 $
当然、コンパイル、実行に成功し、そのまま出力される・・・。
/* ヘッダファイルのインクルード */ #include <stdio.h> /* 標準入出力 */ /* main関数の定義 */ int main(void){ /* 変数の初期化 */ int a = 10; /* aを10に初期化. */ const int b = 100; /* bは100とする.(constが付いているので定数として扱われる. */ /* 値の出力 */ printf("a = %d\n", a); /* aの値を出力. */ printf("b = %d\n", b); /* bの値を出力. */ /* constに代入は不可. */ a = 20; /* aに20を代入.(これは問題なし.) */ b = 200; /* bに200を代入.(これはビルドエラー.) */ /* プログラムの終了 */ return 0; }
このようにaに20, bに200を代入しようとすると、
$ gcc const.c -o const const.c: 関数 ‘main’ 内: const.c:17:3: エラー: 読み取り専用変数 ‘b’ への代入です b = 200; /* bに200を代入.(これはビルドエラー.) */ ^ $
bへの代入はコンパイルエラーとなる・・・。constにより定数として扱われるので・・・。
このようにconstは変数の値を変更されたくない場合に使う・・・。
さて、ポインタの場合は、constの置く位置によって意味がかわる・・・。
/* ヘッダファイルのインクルード */ #include <stdio.h> /* 標準入出力 */ /* main関数の定義 */ int main(void){ /* 変数の初期化 */ int a = 10; /* aを10に初期化. */ const int b = 100; /* bは100とする.(constが付いているので定数として扱われる. */ /* 配列・ポインタの初期化 */ char str1[] = "ABC"; /* str1に"ABC"という文字列をセット. */ char str2[] = "DEF"; /* str2に"DEF"という文字列をセット. */ const char * p = str1; /* ポインタでconstが型名の前の場合は, 参照先の値が変更不可になる. */ char * const q = str2; /* ポインタでconstが変数名の前の場合は, ポインタの値が変更不可になる. */ /* 値の出力 */ printf("a = %d\n", a); /* aの値を出力. */ printf("b = %d\n", b); /* bの値を出力. */ /* constに代入は不可. */ /*a = 20;*/ /* aに20を代入.(これは問題なし.) */ /*b = 200;*/ /* bに200を代入.(これはビルドエラー.) */ /* 値の出力 */ printf("str1 = %s\n", p); /* p( == str1)を出力. */ printf("str2 = %s\n", q); /* q( == str2)を出力. */ /* 変更する. */ *p = 'G'; /* これは変更不可なのでビルドエラー. */ *q = 'H'; /* これは変更可能. */ /* 値の出力 */ printf("str1 = %s\n", p); /* p( == str1)を出力. */ printf("str2 = %s\n", q); /* q( == str2)を出力. */ /* プログラムの終了 */ return 0; }
char型配列str1の先頭アドレスをp, str2の先頭アドレスをqに渡す・・・。
pは型の前にconstを付けるのに対し、qは型の後(変数名の前)にconstを付けている・・・。
これをコンパイルすると、
$ gcc const.c -o const const.c: 関数 ‘main’ 内: const.c:29:3: エラー: 読み取り専用位置 ‘*p’ への代入です *p = 'G'; /* これは変更不可なのでビルドエラー. */ ^ $
ポインタの場合は、型の前だとポインタの参照先の値を変更不可にする・・・。
const <型> * <ポインタ名> /* ポインタの参照先の値が変更不可 */
である・・・。
/* ヘッダファイルのインクルード */ #include <stdio.h> /* 標準入出力 */ /* main関数の定義 */ int main(void){ /* 変数の初期化 */ int a = 10; /* aを10に初期化. */ const int b = 100; /* bは100とする.(constが付いているので定数として扱われる. */ /* 配列・ポインタの初期化 */ char str1[] = "ABC"; /* str1に"ABC"という文字列をセット. */ char str2[] = "DEF"; /* str2に"DEF"という文字列をセット. */ const char * p = str1; /* ポインタでconstが型名の前の場合は, 参照先の値が変更不可になる. */ char * const q = str2; /* ポインタでconstが変数名の前の場合は, ポインタの値が変更不可になる. */ /* 値の出力 */ printf("a = %d\n", a); /* aの値を出力. */ printf("b = %d\n", b); /* bの値を出力. */ /* constに代入は不可. */ /*a = 20;*/ /* aに20を代入.(これは問題なし.) */ /*b = 200;*/ /* bに200を代入.(これはビルドエラー.) */ /* 値の出力 */ printf("str1 = %s\n", p); /* p( == str1)を出力. */ printf("str2 = %s\n", q); /* q( == str2)を出力. */ /* 変更する. */ /**p = 'G';*/ /* これは変更不可なのでビルドエラー. */ *q = 'H'; /* これは変更可能. */ /* 変更する. */ p = str2; /* これは変更可能. */ q = str1; /* これは変更不可なのでビルドエラー. */ /* 値の出力 */ printf("str1 = %s\n", p); /* p( == str1)を出力. */ printf("str2 = %s\n", q); /* q( == str2)を出力. */ /* プログラムの終了 */ return 0; }
これだと、
$ gcc const.c -o const const.c: 関数 ‘main’ 内: const.c:34:3: エラー: 読み取り専用変数 ‘q’ への代入です q = str1; /* これは変更不可なのでビルドエラー. */ ^ $
型の後ろだとポインタを変更不可にする・・・。
<型> * const <変数名> /* ポインタが変更不可 */
である・・・。
最終的にコンパイル成功したものは、
結果は、
$ ./const a = 10こ b = 100 a = 20 b = 100 str1 = ABC str2 = DEF p = HEF q = HEF $
qの参照先の先頭を'H'に変え、pはstr2を指すようにしたので、こうなる・・・。