• ベストアンサー

文字列の宣言(ポインタと配列)

Cでソケット通信などはできるくらい(もちろんできると言っても私のレベルで) になりましたが、文字列を宣言する際に char *str = "ahaha'; char str[] = "ahaha"; の2種類の違いが今イチしっくりきません。 いろんな参考書でこれの説明はありましたが、でも結局なんなんだ、という感じです。 ポインタで宣言するべき時、配列で宣言するべきときが判断できません。 またポインタで宣言するとエラーが出るけど試し配列で宣言してみたら なんか知らんが動いた、ということも多々ありましたが理由がよくわからなかったです。 よろしくお願いいたします。

質問者が選んだベストアンサー

  • ベストアンサー
  • rabbit_cat
  • ベストアンサー率40% (829/2062)
回答No.7

#1、#2の方のとおり、 char *str = "ahaha'; は書き換え不可能な文字列 char str[] = "ahaaha"; は書き換え可能な文字列 っていう違いです。 パソコンのユーザーアプリなんかでは、普通書き換え可能なRAMにしかアクセスできないんで、あんまり違いはないんですが。 小さなメモリ+ROMみたいな組み込みのシステムでは、 char *str = "ahaha'; は、固定文字列(書き換え不可能)で、多くの場合ROMに置かれます。 char str[] = "ahaha'; は、書き換え可能ですから、ROMには置けず、RAMに置かないといけません。(必ずしもスタックに置く必要はないですが)

その他の回答 (8)

  • aris-wiz
  • ベストアンサー率38% (96/252)
回答No.9

>char *strもあればchar str[]もありますが >べつにどちらか片方あればいいんじゃないでしょうか。 これは私の思い込みですが、 この2つはC言語で実装する方法が同じだけであって、 用途としては使い分けるのが正しいと思います。 つまりC言語がこれらの変換を暗黙で行っていたとしても ポインタ変数は、変数の「アドレスを代入できる変数」であり、 配列名は複数の変数の先頭を示すアドレス「複数の変数」です。 違いと言うものは存在していると思います。

  • php504
  • ベストアンサー率42% (926/2160)
回答No.8

プログラム実行時にコードが置かれるメモリは書き換えられるとプログラムが動かなくなるので読み込み専用として保護されます。 この領域に書き込みしようとするとaccess violationのエラーが出て異常終了になります。 char *str = "ahaha'; の場合のポインタはこの書き込み禁止領域のアドレスになるということです。 char str[] = "ahaha"; の場合は読み書き自由なエリアのアドレスになります。

  • koko_u_
  • ベストアンサー率18% (459/2509)
回答No.6

>ただわざわざ2種類用意されている必然性って何なのでしょうか。 >いろんなソースを見ていると >char *strもあればchar str[]もありますが >べつにどちらか片方あればいいんじゃないでしょうか。 char str[] = "ahaaha"; が許されないと、文字配列 str の初期化をいちいちループをまわして(あるいは strncpy で)書かねばならず、面倒なので却下。 char *str = "ahaaha"; が許されないと。。。思い付かん。 多分 char str[] で代替可能だけど、ただのポインタの初期化だから、これだけ禁止にする理由もなかろう。 一つのソースの中で使い方が統一されていれば、特に問題ないと思われますが。 私は大抵前者を変更され得る文字配列の初期化に、後者をマジックナンバーを回避するための定数変数の宣言に使っています。

回答No.5

あと、そういえば Ano.3 の図にもありますが * だと str見て -> アドレス書いてあった。 アドレス見て -> "ahaha" って書いてあった。 の2回メモリアクセス [] だと "ahaha" って書いてあった の1回アクセス ですね。 最適化されるとそうなるか分からないですが。 なんかださっきの結論と逆ですが、違いがでる場所が違うので気にしないで下さい。(無責任) 結論としては、出来たプログラムを逆アセンブルしてみると面白いかもしれません。 多分、どの本にも書いてない事が分かりますよ。(見るときの気持ち次第ですが)

回答No.4

多分どっちでも、目的のプログラムは書けるんじゃないかと思います。 その他思う事としては、 str が どこかの関数のローカル変数なら [] の方は、関数に入る度に スタックに 0x61 0x68 0x61 0x68 0x61 0x00 => "ahaha" と書かないといけないので、ちょっと遅いかもしれません。 (x86のcpuなら 0x68616861 と 0x0061 の2回のアクセスかなぁ?) ただ同様に、 * の場合は、スタックに "ahaha" のアドレスを書かないとダメなの これにも時間がかかります。 (こっちはアドレスなので 32bits 1回) まとめると もっと 文字数が多いと差が出るんじゃないかと思います。 あと > いろんな参考書でこれの説明はありましたが、でも結局なんなんだ、という感じです。 こういう気持はすごく良く分かります。 結局、本って他人が過去に思った疑問に答えてるような部分があるので 自分の疑問には答えてくれませんよね。

  • noocyte
  • ベストアンサー率58% (171/291)
回答No.3

●char *str = "ahaha";   ┌──┐    ┌─┬─┬─┬─┬─┬─┐ str│ ・─┼─→│_a_│_h_│_a_│_h_│_a_│_\0_│   └──┘   └─┴─┴─┴─┴─┴─┘ ●char str[] = "ahaha";   ┌─┬─┬─┬─┬─┬─┐ str│_a_│_h_│_a_│_h_│_a_│_\0_│   └─┴─┴─┴─┴─┴─┘

R-gray
質問者

お礼

みなさんありがとうございます。 ただみなさんのおっしゃっているあたりのことは私も大体理解できているのです。 (すみません、初めに言っておくべきでした。) ただわざわざ2種類用意されている必然性って何なのでしょうか。 いろんなソースを見ていると char *strもあればchar str[]もありますが べつにどちらか片方あればいいんじゃないでしょうか。 あるソースでchar *strと宣言した方は何故char str[]じゃ嫌だったんでしょう。 逆もまた然りです。

  • aris-wiz
  • ベストアンサー率38% (96/252)
回答No.2

int main(void) { char* str = "aaa"; char str2[] = "bbb"; // *str = 'c'; *str2 = 'd'; printf( "%s\n", str ); printf( "%s\n", str2 ); return 0; } 上記のプログラムで、 strは文字リテラルへのポインタになります。 つまり。 「リテラル」つまり「定数」です 何処かの領域[0] = 'a' 何処かの領域[1] = 'a' 何処かの領域[2] = 'a' 何処かの領域[3] = '\0' str = 何処かの領域のアドレス str2は、(文字列の)配列変数です。 str2[0] = 'b' str2[1] = 'b' str2[2] = 'b' str2[3] = '\0' 上記のプログラムで、 *str = 'c'; とできないのは、「定数」であるstrの 先の領域を書き換えようとしている為です。 C++などではこれをDefineの代わりに使用します。 const char* PATH = "c:\tmp\path";

  • koko_u_
  • ベストアンサー率18% (459/2509)
回答No.1

char* str = "ahaaha"; は「どこかの静的な領域に取られた」"ahaaha" にアクセスするために、そのアドレスを str に格納している。 当然、str の指す場所には書き込めない。本来 const char* と宣言するべき char str[] = "ahaaha"; は「自分で確保したスタック領域」を "ahaaha" で初期化。 もちろん、後で str を書換えることも可能。

関連するQ&A