2

const char *それは const char へのポインターであり、一方は char への定数ポインターであることはわかっていchar *constます。これを次のコードでテストしています。

const char *s = "hello";    // Not permitted to modify the string "hello"
char *const t = "world";    // Not permitted to modify the pointer t

s = "hello2";   // Valid
// t = "world2";   // Invalid, gives compilation error

// *(s + 1) = 'a';    // Invalid, gives compilation error
*(t + 1) = 'a';       // Why does this not work?    

最後の行ではエラーは発生しませんが、プログラムが予期せず終了します。が指す文字列の変更がt許可されていないのはなぜですか?

4

4 に答える 4

7

tは文字列リテラルを指しています。文字列リテラルを変更する動作は未定義です。C++ ドラフト標準セクション2.14.5 文字列リテラルの段落12には次のように書かれています (強調鉱山):

すべての文字列リテラルが異なる (つまり、重複しないオブジェクトに格納される) かどうかは、実装で定義されます。文字列リテラルを変更しようとした場合の影響は未定義です。

C99 ドラフト標準の関連セクションは、6.4.5 文字列リテラルの段落6であり、次のように述べられています (強調鉱山):

これらの配列の要素が適切な値を持っている場合、これらの配列が異なるかどうかは指定されていません。プログラムがそのような配列を変更しようとした場合、動作は未定義です。

典型的な最新の Unix プラットフォームでは、読み取り専用セグメントに文字列リテラルがあり、それを変更しようとするとアクセス違反が発生します。次のように、 objdumpを使用して読み取り専用セクションを検査できます。

objdump -s -j .rodata

次の実際のでは、文字列リテラルが実際に読み取り専用セクションにあることがわかります。を追加する必要があったことに注意してくださいprintf。そうしないと、コンパイラが文字列リテラルを最適化してしまいます。` objdumpの出力例:

Contents of section .rodata:
 400668 01000200 776f726c 64002573 0a00      ....world.%s..

別のアプローチは、次のように文字列リテラルtのコピーを含む配列を指すようにすることです。

char r[] = "world";    
char *const t = r ;
于 2013-10-15T03:47:48.160 に答える
3

C の文字列リテラルは公式にはchar[](array of char, not const) の型を持っていますが、C 標準では、変更不可として扱う必要があると明確に述べられています。コンパイラは文字列リテラルを読み取り専用セグメントに配置する傾向があるため、それらを変更しようとするとアクセス違反が発生します。

文字列リテラルは6.4.5、C11 標準 (ISO/IEC 9899:2011) のセクションで説明されています。

于 2013-10-15T03:47:34.737 に答える
1

char*のように として再キャストすることでコンパイラ エラーを回避できますが*((char*)s + 1) = 'a';、他の回答で既に占有されているため、これは未定義の動作であり、文字列リテラルを編集しているため、おそらくセグメンテーション違反が発生します。

于 2013-10-15T03:55:01.927 に答える
1

適切にテストしたい場合は、関数内の文字列を初期化して、初期化が動的になりstrdup()、そのために使用できるようにします。

int
main(int argc, char **argv)
{
    char *d1 = strdup("hello");
    char *d2 = strdup("world");

    const char *s = d1;
    char *const t = d2;

    ...

    free(d1);
    free(d2);
}

d1 変数と d2 変数は主に使用されるため、最後に使用free()して動的割り当てを適切に解放できます。また、他の回答が示唆するように、常に文字列リテラルを として扱いますconst char *

于 2013-10-15T08:13:05.560 に答える