constについて詳しく説明
constは参照先を変更したくない時に使う。
どこにconstが付いているのかによって、代入できない参照先が違ってくる。
データ型にconstを付けた場合
- const int x = 10; → (const int) x = 10;
- int const x = 10; → (int const) x = 10;
この場合は、どちらも変数xが参照先となるためどちらも同じ意味となる。ただ、一般的には1の方の書き方をする。
ポインタにconstを付けた場合
- int* const p = 10; → int (* const) p = 10; // 参照先はp
- const int *p = 10; → (const int) *p = 10; // 参照先は*p
この場合は、参照先が違ってくる。
1の場合、pの値を変更できなくなるので、pに別のアドレスを格納しようとするとエラー
2の場合、*pの値を変更できなくなるので、*pに値を格納しようとするとエラー
int main(void){
int a = 20;
int b = 50;
int* const p1 = &a;
const int *p2 = &a;
*p1 = 30; // OK
p1 = &a; // エラー
*p2 = 30; // エラー
p2 = &b; // OK
return 0;
}
typedefとconstの組合せは注意
typedef char* PCSTR;
const PCSTR str → (const char )*str;
PCSTR const str → char(* const) str;
となるため、参照先が違う
文字列定数(文字列リテラル)とconst
文字列定数で初期化するときには、constを指定しないとエラーになる
char* str = “ABC”; // エラー
これだと、str[5]=’a’;のように書き換えることができるので、「ABC」と3文字+\0の領域しか用意していない場所をはみ出すようなプログラムを書いてもコンパイルエラーとならず、プログラム実行中に異常終了となりバグの原因を作ってしまう。
const char* str = “ABC”; // 正しい
このように記述すると、*strがconstの参照先となりstr[5]=’a’;とするとコンパイルエラーとなるためバグの原因を作らずに済む。
const char* str = “ABC”;
str = “DEFGH”;
このようにstrはconstの参照先となっていないため、strに格納するアドレスを変更することは可能。
どちらも変更したくないのであれば、下記のように2か所にconstをつける。
const char* const str1 = “ABC”;
int main(void) {
char* str = "ABC"; // エラー
const char* str = "ABC";
str = "DEFGH";
const char* const str1 = "ABC";
str1[5] = 'X'; // エラー
str1 = "DEFG"; // エラー
return 0;
}