アプリ版:「スタンプのみでお礼する」機能のリリースについて

char* 宣言での配列要素アクセスについて

char*型で宣言したポインタ変数に対して
配列の要素でアクセスすると落ちてしまいます。

理由がよくわかりません。
以下コードになります。

(コードA)
char* pA = "123456789";
pA[2] = 'A';

以下のコードの場合は問題ありません。

(コードB)
char pB[] = "123456789";
pB[2] = 'B';

両者の違いがいまいちよく分かりません。
コードAでpA[2]のアドレスを確認すると、
pAのアドレス[+2]を指しているので問題ないともうのですが、
間違っているのでしょうか?

pAに対して特別な操作はしていません。

ご教授お願いいたします。

A 回答 (4件)

>char* pA = "123456789";


>pA[2] = 'A';

メモリ上のどこかに"123456789"が格納され、その先頭アドレスがpAに格納されます。
メモリ上のどこかに格納されている"123456789"は「文字列定数」となります。
「定数」なので、通常は書き換えは許可されません。

>char pB[] = "123456789";
>pB[2] = 'B';

メモリ上(ローカル変数ならたいていはスタック領域上)に10バイトの領域を確保し、
その領域の初期値として"123456789"を格納しています。
こちらは通常内容が変化するものとして使用されるので、書き換えは可能です。

http://www9.plala.or.jp/sgwr-t/c/sec10-3.html
の【文字列リテラル】を参照されるとよいでしょう。


char* pA = "123456789";
char* pB = "123456789";
と記述した場合、指している文字列は同じですからコンパイラの最適化によってはpAとpBが同じアドレスを指す場合があります。
さて、文字列リテラルの書き換えを許可していたとて、*(pA+1) = 'B'が可能だった場合にpBが指す文字列はどうなるでしょう?
    • good
    • 0
この回答へのお礼

Wr5様

回答ありがとうございます。
よく分かりました。

参考URLもわかりやすかったです。

お礼日時:2010/07/22 11:49

コードAの場合、文字列を格納するだけの領域を確保したうえで文字列をその領域にコピーするようにしなくてはなりません。



char* pA = (char*) malloc(10); /* 文字列のサイズ+1 のバッファを確保 */
strcpy(pA, "123456789");
pA[2] = 'A';

コードAのように
char* pA = "123456789";
としてしまうと、読み取り専用メモリに文字列"123456789"が格納されてしまい、その領域を書き換えようとすると落ちてしまいます。
    • good
    • 0
この回答へのお礼

ryoyama様

回答ありがとうございます。
参考になりました。

お礼日時:2010/07/22 11:53

コードA のように書いた場合, pA がさす文字列リテラルを変更してはいけないことになっています. イメージとしては, コードA では「文字列リテラル "123456789" はプログラムが直接管理しないどこかにあって pA はその領域を指す」, コードB は「プログラムで必要な領域を pB として確保しそこに文字列リテラル "123456789" と同じものを入れておく」という感じでしょうか.


本来文字列リテラルは「定数」であり, その型は const char [] であるべきものです. C では const のつかない char [] ですが, これは「そもそも const というものが存在しなかったはるか遠い過去」との互換性によるものであり, 「変更できないものである」と考えるべきです. ちなみに C++ では const char [] だけど特例で char * な変数にも代入できる (がそのような操作はすべきではない).
    • good
    • 0
この回答へのお礼

Tacosan様

回答ありがとうございます。
参考になりました。

お礼日時:2010/07/22 11:52

コードAは、(一般的に)書き換え不能領域に配置される文字列"123456789"の先頭アドレスをpAに与えます。


で、書き換え不能領域を書き変えようとするのでメモリ保護例外が出ます。
#環境によってたまーに例外があるので注意

コードBは、配列pBを"123456789"の値で初期化します。
こちらは書き換え可能領域内にあるので、自由に書き換えられます。

従って、配列のようにアクセスしたのが原因ではなくコードAでは*(pA+2)='A';でも同様にコケます。
    • good
    • 0
この回答へのお礼

D-Matsu様

回答ありがとうございます。
参考になりました。

お礼日時:2010/07/22 11:51

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