プログラミング初心者です


ポインタを使った文字列の初期化でつまづいています.
char str[] = "hoge";
char* str2 = "piyo";
のように初期化した後では

printf("%c\n",str[0]); ->hが出力
printf("%c\n",str2[0]); ->pが出力

となるのですが,

str[0] = 'A'; <-OK
str2[0] = 'A'; <-エラー
とするとプログラムが落ちてしまいます.

ポインタの知識が乏しいのか,このエラーの原因がわかりません.
なにか参考になるページがありましたら教えていただけないでしょうか?

よろしくお願いいたします.

回答の条件
  • 1人5回まで
  • 登録:
  • 終了:2007/03/06 14:58:23
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。

ベストアンサー

id:Kumappus No.3

回答回数3784ベストアンサー獲得回数185

ポイント30pt

たぶん、実行時エラーとしてセグメンテーションエラーが出たのだと思います。

char str[] = "hoge";
char* str2 = "piyo";

上の行は"hoge"という文字列を「データ格納領域(データセグメント)」にある配列strにコピーします。

下の行は"piyo"という文字列が書かれた「プログラム格納領域(コードセグメント)」のアドレスをstr2に代入します。

一般にプログラム格納領域は変化してはいけない(読み出しのみ)になっているために書き込みをしようとするとOS(CPU)がエラーを出すのです。

これが組み込み用の8bitマイコンなんかだとそういうセグメントの概念がないのでたぶんエラーは出ないです。

もしポインターでやるのなら

char* p = malloc(5);

strcpy( p, "piyo");

みたいにポインタが、メモリ割り当て関数malloc()で割り当てられたデータ格納領域を指すようにするなどの必要があります。

http://itpro.nikkeibp.co.jp/article/COLUMN/20061023/251565/?ST=d...

http://itpro.nikkeibp.co.jp/article/COLUMN/20061128/255135/?ST=d...

id:rockafeller

char str[] = "hoge";

char* str2 = "piyo";

では同じことをしているのかと思っていたのですが,全然意味が違うのですね・・・

2007/03/06 14:54:37

その他の回答3件)

id:TONTON3 No.1

回答回数212ベストアンサー獲得回数4

ポイント20pt

char str[] = "hoge";

char* str2 = "piyo";

str2に文字というか数値を格納する場合

メモリを割り当てたり strのポインタにすればよいでしょう

str2 を maloc してみてはいかがでしょうか?

id:rockafeller

ありがとうございます.

malocを使うと正常に動作しました.

2007/03/06 14:52:13
id:Mook No.2

回答回数1314ベストアンサー獲得回数393

ポイント30pt

前者は動的領域にデータが確保されるので、

char str[] = "hoge";

char str[5] = { 'h', 'o', 'g', 'e', '\0' };

と等価ですが、後者はコンパイラによって定義されたデータ領域を指すポインタなので、その領域を変更することは動作的に正しくません。


コンパイラによって動くこともあるかもしれませんが、それは偶然(コンパイラの仕様)であって、データが静的領域を指す場合、今回のように access violation で落ちても、それは正常な動作です。


C言語 ポインタ完全制覇

C言語のポインタ

id:rockafeller

データ領域という概念を知りませんでした.

ありがとうございました.

2007/03/06 14:52:56
id:Kumappus No.3

回答回数3784ベストアンサー獲得回数185ここでベストアンサー

ポイント30pt

たぶん、実行時エラーとしてセグメンテーションエラーが出たのだと思います。

char str[] = "hoge";
char* str2 = "piyo";

上の行は"hoge"という文字列を「データ格納領域(データセグメント)」にある配列strにコピーします。

下の行は"piyo"という文字列が書かれた「プログラム格納領域(コードセグメント)」のアドレスをstr2に代入します。

一般にプログラム格納領域は変化してはいけない(読み出しのみ)になっているために書き込みをしようとするとOS(CPU)がエラーを出すのです。

これが組み込み用の8bitマイコンなんかだとそういうセグメントの概念がないのでたぶんエラーは出ないです。

もしポインターでやるのなら

char* p = malloc(5);

strcpy( p, "piyo");

みたいにポインタが、メモリ割り当て関数malloc()で割り当てられたデータ格納領域を指すようにするなどの必要があります。

http://itpro.nikkeibp.co.jp/article/COLUMN/20061023/251565/?ST=d...

http://itpro.nikkeibp.co.jp/article/COLUMN/20061128/255135/?ST=d...

id:rockafeller

char str[] = "hoge";

char* str2 = "piyo";

では同じことをしているのかと思っていたのですが,全然意味が違うのですね・・・

2007/03/06 14:54:37
id:dev_zer0 No.4

回答回数332ベストアンサー獲得回数25

ポイント30pt

おそらくC言語だと思われますが、下記のC-FAQ 1.32を参照してください

http://www.kouno.jp/home/c_faq/c1.html#32


> char str[] = "hoge";

> str[0] = 'A'; <-OK

これは5つの要素を持つ配列を定義してその0番目を書き換えただけなので問題ありません

# str[5] = 'A';とかすると未定義動作になります

# 未定義動作とは「何が起こってもよい」ということです

# 別のコンパイラだとプログラムが落ちない可能性もありますし、

# コンパイルオプションの変更や、何か処理を追加するだけで

# 動いたり、動かなくなったりします。


> char* str2 = "piyo";

> str2[0] = 'A'; <-エラー

これは文字列リテラルを指すポインタを定義して、

文字列リテラルを書き換えてしまったので未定義動作となります。


ポインタを使うときはその指し示す先に何があるのかを意識する必要があります。

id:rockafeller

ありがとうございました.

後者の書き方だと,ポインタの先が文字列リテラルのアドレスになるということがわかりました.

2007/03/06 14:55:48
  • id:Kumappus
    じじいなもんでかなり古い書き方になってます。
    ちょっとコード書いてアセンブラ出力させて確認したりして;p

    文字列リテラル
    http://www9.plala.or.jp/sgwr-t/c/sec10-3.html
    って呼びかたのほうが今はしっくりくるようですね。
  • id:rockafeller
    文字列リテラルと言われるとスッキリ理解できました.
    ありがとうございました.

この質問への反応(ブックマークコメント)

トラックバック

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません