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

Cでソケット通信などはできるくらい(もちろんできると言っても私のレベルで)
になりましたが、文字列を宣言する際に
char *str = "ahaha';
char str[] = "ahaha";

の2種類の違いが今イチしっくりきません。
いろんな参考書でこれの説明はありましたが、でも結局なんなんだ、という感じです。
ポインタで宣言するべき時、配列で宣言するべきときが判断できません。
またポインタで宣言するとエラーが出るけど試し配列で宣言してみたら
なんか知らんが動いた、ということも多々ありましたが理由がよくわからなかったです。
よろしくお願いいたします。

A 回答 (9件)

>char *strもあればchar str[]もありますが


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

プログラム実行時にコードが置かれるメモリは書き換えられるとプログラムが動かなくなるので読み込み専用として保護されます。


この領域に書き込みしようとするとaccess violationのエラーが出て異常終了になります。
char *str = "ahaha';
の場合のポインタはこの書き込み禁止領域のアドレスになるということです。
char str[] = "ahaha";
の場合は読み書き自由なエリアのアドレスになります。
    • good
    • 0

#1、#2の方のとおり、


char *str = "ahaha'; は書き換え不可能な文字列
char str[] = "ahaaha"; は書き換え可能な文字列
っていう違いです。

パソコンのユーザーアプリなんかでは、普通書き換え可能なRAMにしかアクセスできないんで、あんまり違いはないんですが。

小さなメモリ+ROMみたいな組み込みのシステムでは、
char *str = "ahaha';
は、固定文字列(書き換え不可能)で、多くの場合ROMに置かれます。

char str[] = "ahaha';
は、書き換え可能ですから、ROMには置けず、RAMに置かないといけません。(必ずしもスタックに置く必要はないですが)
    • good
    • 0

>ただわざわざ2種類用意されている必然性って何なのでしょうか。


>いろんなソースを見ていると
>char *strもあればchar str[]もありますが
>べつにどちらか片方あればいいんじゃないでしょうか。

char str[] = "ahaaha";

が許されないと、文字配列 str の初期化をいちいちループをまわして(あるいは strncpy で)書かねばならず、面倒なので却下。

char *str = "ahaaha";

が許されないと。。。思い付かん。
多分 char str[] で代替可能だけど、ただのポインタの初期化だから、これだけ禁止にする理由もなかろう。

一つのソースの中で使い方が統一されていれば、特に問題ないと思われますが。
私は大抵前者を変更され得る文字配列の初期化に、後者をマジックナンバーを回避するための定数変数の宣言に使っています。
    • good
    • 0

あと、そういえば


Ano.3 の図にもありますが

* だと
str見て -> アドレス書いてあった。
アドレス見て -> "ahaha" って書いてあった。
の2回メモリアクセス

[] だと
"ahaha" って書いてあった
の1回アクセス

ですね。
最適化されるとそうなるか分からないですが。
なんかださっきの結論と逆ですが、違いがでる場所が違うので気にしないで下さい。(無責任)

結論としては、出来たプログラムを逆アセンブルしてみると面白いかもしれません。
多分、どの本にも書いてない事が分かりますよ。(見るときの気持ち次第ですが)
    • good
    • 0

多分どっちでも、目的のプログラムは書けるんじゃないかと思います。



その他思う事としては、
str が どこかの関数のローカル変数なら

[] の方は、関数に入る度に スタックに
0x61 0x68 0x61 0x68 0x61 0x00 => "ahaha"
と書かないといけないので、ちょっと遅いかもしれません。
(x86のcpuなら 0x68616861 と 0x0061 の2回のアクセスかなぁ?)

ただ同様に、
* の場合は、スタックに "ahaha" のアドレスを書かないとダメなの
これにも時間がかかります。
(こっちはアドレスなので 32bits 1回)

まとめると もっと 文字数が多いと差が出るんじゃないかと思います。


あと
> いろんな参考書でこれの説明はありましたが、でも結局なんなんだ、という感じです。
こういう気持はすごく良く分かります。
結局、本って他人が過去に思った疑問に答えてるような部分があるので
自分の疑問には答えてくれませんよね。
    • good
    • 0

●char *str = "ahaha";


  ┌──┐    ┌─┬─┬─┬─┬─┬─┐
str│ ・─┼─→│_a_│_h_│_a_│_h_│_a_│_\0_│
  └──┘   └─┴─┴─┴─┴─┴─┘


●char str[] = "ahaha";
  ┌─┬─┬─┬─┬─┬─┐
str│_a_│_h_│_a_│_h_│_a_│_\0_│
  └─┴─┴─┴─┴─┴─┘
    • good
    • 0
この回答へのお礼

みなさんありがとうございます。
ただみなさんのおっしゃっているあたりのことは私も大体理解できているのです。
(すみません、初めに言っておくべきでした。)

ただわざわざ2種類用意されている必然性って何なのでしょうか。
いろんなソースを見ていると
char *strもあればchar str[]もありますが
べつにどちらか片方あればいいんじゃないでしょうか。
あるソースでchar *strと宣言した方は何故char str[]じゃ嫌だったんでしょう。
逆もまた然りです。

お礼日時:2007/05/31 22:04

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";
    • good
    • 0

char* str = "ahaaha";



は「どこかの静的な領域に取られた」"ahaaha" にアクセスするために、そのアドレスを str に格納している。
当然、str の指す場所には書き込めない。本来 const char* と宣言するべき

char str[] = "ahaaha";

は「自分で確保したスタック領域」を "ahaaha" で初期化。
もちろん、後で str を書換えることも可能。
    • good
    • 0

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