たのしい工学

プログラミングを学んで、モノをつくりたいひと、効率的に仕事をしたい人のための硬派なブログになりました

[解説] C++ 文字列リテラル ポインタ

   

C++で配列を文字列リテラルで初期化するには

const char* anyarray[] = {
        "Fomer value is less than latter.",
        "Both value is equal.",
        "Former value is greater than latter.",
    };

このように書けます。

 anyarray は配列でした。しかし、別に配列でなくてもこの初期化は可能です。

const char* str = "string";

これは下記のように書くことも可能です

const char* str;
str = "string";
 この " " は何やらアドレスを返します。

 この " " で囲まれた文字列のことはリテラル文字列と呼ばれます。これは静的なデータです。メモリ上の静的な領域のどこかにこの文字列が置かれます。

 そして、これをポインタに代入する式は、ポインタにそのアドレスを渡す式になるのです。
よく考えてみれば、文字列を受ける関数
例)void Func(const char* str);
に " " で囲まれた文字列を渡したことが何度もあると思います。その時の str の値は何なのか考えたことはあるでしょうか? まさにそれがリテラル文字列へのアドレスなのです。

 このように、ポインタにリテラル文字列を代入すると、ポインタにはそのリテラル文字列へのアドレスが代入されるのです。

 ここで注意することは、リテラル文字列へのアドレスが入っているので、str[0] = 0; などをするとリテラル文字列を直接書き換えることになるということです。環境によるのですが、リテラル文字列を書き換えようとするとエラーになることが多いです。昔の環境ではエラーにならないこともありますが、そういう場合でもリテラル文字列を書き換えてはいけません。

 なので、リテラル文字列を受けるポインタには const を必ず付けましょう

 また、リテラル文字列は静的なデータなので、寿命はプログラムが始まってから終わるまでです。

 また、上の anyarray も関数に入る毎に毎回初期化するのは無駄なので、

static const char* anyarray[] = {
        "Fomer value is less than latter.",
        "Both value is equal.",
        "Former value is greater than latter.",
    };

と、staticをつけて静的にしてしまうといいでしょう。

 と、リテラル文字列での初期化の話をしました。では、配列をリテラル文字列で初期化したとき、例えば

char str[] = "This is string.";
としたとき、str はリテラル文字列を直接指しているのでしょうか? 答はノーです。

 str という配列は "This is string." という配列で初期化されるだけです。つまりは、

char str[] = {
'T', 'h', 'i', 's', ' ', 'i', 's', ' ', 's', 't', 'r', 'i', 'n', 'g', '.', 0,
};
と同じ事になるわけです。

 str は普通の配列であり、書き換えても問題ありません。str が自動変数なら str の寿命はそのブロック内に限られ、そのブロックを抜けると値は保証されません。なので、自動変数 str を関数から返すということは絶対にしてはなりません。

 このことは、初期化というのは普通の式とはちょっと違うのだということを表しています。初期化と代入式との違いというのは他にもあります。初期化と代入式は厳密には区別されるものなのです。

以上

 - コンピュータサイエンス ,