- ベストアンサー
C言語での文字列代入について教えてください
- C言語での文字列代入について質問があります。具体的には、char*型の変数に文字列を代入する際、メモリを取らずに代入できる理由と、後から変数の値を別の文字列で書き換えることができる理由について知りたいです。
- また、質問者の開発環境がVS.2005 VC++であることも教えてください。
- よろしくお願いします。
- みんなの回答 (8)
- 専門家の回答
質問者が選んだベストアンサー
>char* moji; mojiはchar*型の変数です。 >moji = "right Test \n"; メモリ上のどこかに配置されている「文字列定数」のアドレスを代入しています。 # コンパイラとリンカがよろしく確保しています。 >moji = "dot 255 left up down \n"; 同じく、メモリ上の別の場所に配置されている「文字列定数」のアドレスを代入しています。 別に不思議なことではありません。 アドレスを格納するだけの変数の領域は >char* moji; で確保されているのですから。 ただし…moji経由で内容を書き換えようとすると、不正終了する可能性があります。 moji = "right Test \n"; *(moji+1) = 'I'; とか、 moji = "right Test \n"; strcat(moji, "dot 255 left up down \n"); とか。 不正終了しない場合は…… moji = "right Test \n"; *(moji+1) = 'I'; moji = "right Test \n"; で、2回目の代入した際に書き換わっている可能性があります。
その他の回答 (7)
- wormhole
- ベストアンサー率28% (1626/5665)
やってることは「文字列での代入」ではなくて 「ポインタ値の代入」なのでできて当然。
お礼
なるほど理解しました。
- asuncion
- ベストアンサー率33% (2127/6289)
#1さんの投稿にある「明らかな間違い」というのが、明らかな間違いです。 たまたま動いているわけでも何でもなく、正しいコードです。 コンパイル時に "right Test \n" とか "dot 255 left up down \n" とかのアドレスを(コンパイラーが)決めてくれていて、 変数mojiにそれらを代入しているだけのことです。
お礼
なるほど分かりました。 開発環境、PC環境などでは左右されないということですね。
- Tacosan
- ベストアンサー率23% (3656/15482)
「ポインタそのもの」と「ポインタが指している内容」とは明確に区別してください. その上で, 「こういったこと」が「どういったこと」であるのか説明できますか? 以下余談: たしかに「文字列リテラルを char* で扱う」のはあまりいいことではないけど, これがきちんと動くことは環境によらない>#3 し, まして「明らかな間違い」と言い切っちゃうのはいかがなものかと>#1. ついでに C では「(配列の初期化で用いられていない) 文字列リテラル」の個々の文字は (const char ではなく) 「ただの char」 (ただし変更不可) だったりします>#5. C++ だと const char (でも文字列リテラル全体は char* 変換可能) と, これはこれでややっこしかったりしますが.
お礼
char* を使って文字列リテラルを扱うことが環境によらないこと なんですね。たとえばVC++6.0でもこうなると。 自分の感想なんですが、char* だけで文字列リテラルを扱う場 合、前の質問者さんが指摘した部分で変数に代入する場合は 注意が必要だということですね。 それに気を付けていれば扱いやすいかもしれないと思いました。 今までは、 malloc, newして代入してたんで、このやり方を知ら なかったです。
- tadys
- ベストアンサー率40% (856/2135)
C言語の変数には{名前、アドレス、属性、値}というものが付随しています。 例えば、 int abc = 123 ; という変数では abc という名前と int という属性と 123 という値を持ちます。 アドレスは、静的変数の場合はコンパイラが決定しますが、動的変数では実行時に決定されます。 名前、アドレス、属性は変更できませんが、値は変更できます。 (属性については一時的な変更は可能) 名前はコンパイラだけが使用し、プログラムから操作する事は出来ません。 char* moji; の場合、moji という名前で、char へのポインタという属性を持ちます。 この場合の moji は動的変数なので関数が呼び出された時にアドレスが決まります。 その値は関数が呼び出された時点では不定です。 char へのポインタという属性は、その変数の値が char という属性を持つ別の変数のアドレスを示すという事を意味します。 (この、ポインタ変数というのが分かりにくい原因ですね) moji = "right Test \n"; の場合、"right Test \n"という文字列をコンパイラが用意します。 この文字列の名前とアドレスはコンパイラが自動的に決めます。 値は"right Test \n"という文字列で、属性は const char です。 moji = "right Test \n"; を実行すると moji の値を"right Test \n"という文字(列)のアドレスに置き換えます。 moji の値は正しく"right Test \n"という文字列を示しているので printf() で出力する事が出来ます。 moji = "dot 255 left up down \n";では、 moji の値が"dot 255 left up down \n"; のアドレスに置き換えられるます。 moji の値は正しく"dot 255 left up down \n"を示しているので printf() で出力する事が出来ます。 "right Test \n" という文字列は const char という属性を持ちます。 const という属性は書き換え不能、または書き換え禁止という意味を持ちます。 無理に書き換えた時の動作は環境に依存します。
お礼
回答ありがとうございます。 ポインタどうしの代入だったんですね。
- D-Matsu
- ベストアンサー率45% (1080/2394)
ポインタに対する代入演算子はmemcpyやstrcpyのようにポインタが示す先を書き換えるのではなく、ポインタそのものを置き換えるだけです。
お礼
回答ありがとうございます。 moji = "right Test \n"; 上の文は文字列定数のアドレスをmojiに代入している ということですね。
実行できるかどうかはコンパイラなど使用する環境によりますが、あまりお行儀のよいソースでは無いように思います。
お礼
開発環境の差によってできるできないが決まるようですね。 >あまりお行儀のよいソースでは無いように思います。 やはりこれはまずいんでしょうかね。
- black2005
- ベストアンサー率32% (1968/6046)
”たまたま””偶然”です。 明らかな間違いなので、表示出来たからと言って良しとしないことです。
お礼
回答ありがとうございます。 よろしくないようですね。 たまたまというのは開発環境の差でしょうか。
お礼
なるほど # コンパイラとリンカが文字列定数のアドレスを用意しているため それを代入しているんですね。 昔のコンパイラならエラーだったはずなのですが。