3

文字列リテラルと C 文字列についていくつか質問があります。

したがって、次のようなものがある場合:

char cstr[] = "c-string";

私が理解しているように、文字列リテラルは、たとえばアドレス 0xA0 から始まり 0xA9 で終わるなど、終端の null バイトを使用してメモリ内に作成され、そこからアドレスが返されるか、型 char [ ] にキャストされます。住所・アドレス。

これを実行することは合法です:

for (int i = 0; i < (sizeof(array)/sizeof(char)); ++i)
    cstr[i] = 97+i;

この意味で、型 char [ ] にキャストされている限り、文字列リテラルを変更できますか?

しかし、通常のポインターでは、メモリ内の文字列リテラルを指すと、ほとんどのコンパイラが割り当てられたメモリを定数の下限アドレス空間で「読み取り専用」としてマークするため、内容を変更できないことがわかりました。

char * p = "const cstring";
*p = 'A'; // illegal memory write

私が理解しようとしているのは、配列のように char * 型が文字列リテラルを指して定数を変更できないのはなぜですか? 文字列リテラルが char [ ] のように char * にキャストされないのはなぜですか? ここで間違った考えを持っている場合、または完全に間違っている場合は、お気軽に修正してください。

4

4 に答える 4

4

あなたが見逃しているビットは、これが次のような小さなコンパイラの魔法です:

char cstr[] = "c-string"; 

実際には次のように実行します。

char *cstr = alloca(strlen("c-string")+1);
memcpy(cstr,"c-string",strlen("c-string")+1);

そのビットはわかりませんが、多かれ少なかれ、コードがコンパイルされるものです。

于 2011-10-06T03:41:19.987 に答える
2

char cstr[] = "something";バイト's'、'o'、'm'、..に初期化された自動配列を宣言しています。

char * cstr = "something";一方、は、リテラル「何か」のアドレスに初期化された文字ポインタを宣言しています。

于 2011-10-06T03:36:28.040 に答える
1
char cstr[] = "c-string";

これにより、「c-string」がスタック上のchar配列にコピーされます。このメモリに書き込むことは合法です。

char * p = "const cstring";
*p = 'A'; // illegal memory write

「c-string」や「constcstring」などのリテラル文字列は、バイナリのデータセグメントに存在します。この領域は読み取り専用です。pの上はこの領域のメモリを指しており、その場所に書き込むことは違法です。C ++ 11以降、これは以前よりも強力に適用され、代わりに作成する必要const char* pがあります。

ここに関連する質問。

于 2011-10-06T03:37:18.103 に答える
1

最初のケースでは、文字の実際の配列を作成しています。そのサイズは、初期化するリテラルのサイズ(8 + 1バイト)によって決まります。cstr変数にはスタック上のメモリが割り当てられ、文字列リテラルの内容コード内の別の場所、場合によってはメモリの読み取り専用部分にあります)がこの変数にコピーされます。

2番目のケースでは、ローカル変数pにもスタック上のメモリが割り当てられますが、その内容は、初期化する文字列リテラルのアドレスになります。

したがって、文字列リテラルは読み取り専用メモリに配置されている可能性があるため、一般に、ポインタを介して文字列リテラルを変更しようとするのは安全ではありませんp(うまくいく場合とそうでない場合があります)。一方、cstr配列はリテラルから初期化されたばかりのローカルコピーであるため、配列を使用して何でも実行できます。

(1つだけ注意してください:cstr変数はchar型の配列であり、ほとんどのコンテキストでは、これはその配列の最初の要素へのポインターに変換されます。これに対する例外は、たとえばsizeof演算子です。これは配列全体のサイズを計算します。最初の要素への単なるポインタではありません。)

于 2011-10-06T03:38:12.453 に答える