dポイントプレゼントキャンペーン実施中!

こんにちは。
C言語を勉強しているのですが、どうしても分からないことがあるので質問しました。
まず下記のソースを見てください。

#include <stdio.h>

int main()
{
char* moji;

moji = "right Test \n";

printf(" moji = %s\n", moji);

moji = "dot 255 left up down \n";

printf(" moji = %s\n", moji);

getchar();
return 0;
}
char* mojiがメモリを取らずに代入できているのですがこういった事が可能なのは何故でしょうか?
その後もmojiの変数を別の文字列定数で書き換えています。
こういったことはできなかったはずなんですがどうしてでしょうか?
自分の開発環境だとVS.2005 VC++です。
よろしくおねがいします。

A 回答 (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回目の代入した際に書き換わっている可能性があります。
    • good
    • 0
この回答へのお礼

なるほど
# コンパイラとリンカが文字列定数のアドレスを用意しているため
それを代入しているんですね。
昔のコンパイラならエラーだったはずなのですが。

お礼日時:2012/04/05 23:00

やってることは「文字列での代入」ではなくて


「ポインタ値の代入」なのでできて当然。
    • good
    • 0
この回答へのお礼

なるほど理解しました。

お礼日時:2012/04/05 23:11

#1さんの投稿にある「明らかな間違い」というのが、明らかな間違いです。


たまたま動いているわけでも何でもなく、正しいコードです。
コンパイル時に
"right Test \n"
とか
"dot 255 left up down \n"
とかのアドレスを(コンパイラーが)決めてくれていて、
変数mojiにそれらを代入しているだけのことです。
    • good
    • 0
この回答へのお礼

なるほど分かりました。
開発環境、PC環境などでは左右されないということですね。

お礼日時:2012/04/05 23:11

「ポインタそのもの」と「ポインタが指している内容」とは明確に区別してください. その上で, 「こういったこと」が「どういったこと」であるのか説明できますか?



以下余談:

たしかに「文字列リテラルを char* で扱う」のはあまりいいことではないけど, これがきちんと動くことは環境によらない>#3 し, まして「明らかな間違い」と言い切っちゃうのはいかがなものかと>#1.

ついでに C では「(配列の初期化で用いられていない) 文字列リテラル」の個々の文字は (const char ではなく) 「ただの char」 (ただし変更不可) だったりします>#5. C++ だと const char (でも文字列リテラル全体は char* 変換可能) と, これはこれでややっこしかったりしますが.
    • good
    • 0
この回答へのお礼

char* を使って文字列リテラルを扱うことが環境によらないこと
なんですね。たとえばVC++6.0でもこうなると。

自分の感想なんですが、char* だけで文字列リテラルを扱う場
合、前の質問者さんが指摘した部分で変数に代入する場合は
注意が必要だということですね。
それに気を付けていれば扱いやすいかもしれないと思いました。
今までは、 malloc, newして代入してたんで、このやり方を知ら
なかったです。

お礼日時:2012/04/05 23:10

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 という属性は書き換え不能、または書き換え禁止という意味を持ちます。
無理に書き換えた時の動作は環境に依存します。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
ポインタどうしの代入だったんですね。

お礼日時:2012/04/05 23:05

ポインタに対する代入演算子はmemcpyやstrcpyのようにポインタが示す先を書き換えるのではなく、ポインタそのものを置き換えるだけです。

    • good
    • 0
この回答へのお礼

回答ありがとうございます。

moji = "right Test \n";
上の文は文字列定数のアドレスをmojiに代入している
ということですね。

お礼日時:2012/04/05 23:02

実行できるかどうかはコンパイラなど使用する環境によりますが、あまりお行儀のよいソースでは無いように思います。

    • good
    • 0
この回答へのお礼

開発環境の差によってできるできないが決まるようですね。
>あまりお行儀のよいソースでは無いように思います。
やはりこれはまずいんでしょうかね。

お礼日時:2012/04/05 23:01

”たまたま””偶然”です。


明らかな間違いなので、表示出来たからと言って良しとしないことです。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
よろしくないようですね。
たまたまというのは開発環境の差でしょうか。

お礼日時:2012/04/05 22:55

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!