最初にすべきことは、comp.lang.cFAQのセクション6を読むことです。
文字列リテラル"hello"
はタイプの式ですchar[6]
(「hello」の場合は5文字、終了の場合は1文字'\0'
)。これは、静的ストレージ期間を持つ匿名配列オブジェクトを参照し、プログラムの起動時にこれらの6文字の値を含むように初期化されます。
ほとんどのコンテキストでは、配列型の式は、配列の最初の要素へのポインターに暗黙的に変換されます。例外は次のとおりです。
- それがの引数である場合
sizeof
(sizeof "hello"
ポインタのサイズではなく、6を生成します);
_Alignof
(C11の新機能)の引数の場合。
- 単項の引数の場合
&
(&arr
最初の要素ではなく、配列全体のアドレスを生成します。同じメモリ位置、異なるタイプ)。と
- 配列オブジェクトを初期化するために使用される初期化子の文字列リテラルの場合(
char s[6] = "hello";
ポインターだけでなく、配列全体をコピーします)。
これらの例外はいずれもコードには適用されません。
char *ptr;
ptr = "hello";
したがって、式は、前述の匿名配列オブジェクト"hello"
の最初の要素()へのポインタに変換されます(「減衰」します) 。'h'
したがって、、およびメモリを*ptr == 'h'
進んで他の文字にアクセスできます:、、、、、および。これはあなたがそれにフォーマットを与えるとき何をするかです。ptr
'e'
'l'
'l'
'o'
'\0'
printf()
"%s"
文字列リテラルに関連付けられているその匿名配列オブジェクトは読み取り専用ですが、ではありませんconst
。つまり、その配列またはその要素のいずれかを変更しようとすると、未定義の動作が発生します(標準で明示的に指定されているため)。ただし、コンパイラは必ずしもそれについて警告するわけではありません。(C ++は文字列リテラルを作成しますconst
。Cで同じことを行うと、言語に追加される前に記述された既存のコードが壊れてしまいconst
ます。)したがって、"hello"
-の要素を変更することはできません。少なくとも試してはいけません。また、試してみた場合にコンパイラに警告を表示するには、ポインタをconst
次のように宣言する必要があります。
const char *ptr; /* pointer to const char, not const pointer to char */
ptr = "hello";
-Wwrite-strings
(gccには、文字列リテラルをとして処理するオプションがありますconst
。これにより、標準に関する限り有効なCコードについて警告が表示されますが、そのようなコードはおそらく使用するように変更する必要がありますconst
。)