2011-10-25 3 views
2

これら2つの初期化の違いは何ですか?C "文字列" init - これは良いですか?

char a[] = "string literal"; 

char *p = "string literal"; 
+0

重複:stackoverflow.com/questions/7886972/difference-between-char-and-char – tinman

+0

これが何度も尋ねられた場合、人々はなぜ閉じるのではなく答えるのですか? – sidyll

+1

@sidyll:人々は重複をチェックするのではなく、担当者を得るために質問に答えます。 – tinman

答えて

3

それぞれは、(少なくとも概念的には)読み取り専用の静的メモリで文字列リテラルを作成するよう強制します。

最初は、それを使って配列の内容を初期化します。文字列リテラルは、サイズを選択して初期化するために使用されます。

2番目の文字列は、元の文字列リテラルに直接ポインタを作成します。

これらの間には、本当に良いことも悪いこともありません。彼らはただ違っている。たとえば、配列は通常、より多くのメモリを使用します(文字列リテラルがあり、配列内に文字列リテラルの完全なコピーがあります)。ただし、そうでなければ通常の配列なので、必要に応じて変更することができます。

文字列リテラルへのポインタは、しばしばメモリを節約します。また、異なる値をポインタに代入して、異なる時間に異なる文字列リテラルを指すようにすることもできます。しかしではなくですが、それが指すデータを変更することができます。そうすることで、未定義の動作が得られます。

17

2つは同じように見えますが、しばしば互換的に使用されますが、異なる意味を持ちます。最初の行:

... NULターミネーターを含め、文字列リテラルを保持するのに十分な大きさの配列を作成します。この配列は、指定した文字列リテラルで初期化されます。このバージョンの利点の1つは、アレイを後で変更できることです。また、配列のサイズはコンパイル時でもわかりますので、sizeof演算子を使用してそのサイズを決定することができます。

printf("%u\n",unsigned(sizeof(a))); // Will display 15, which is the array's size 
            // including the NUL terminator 

二行目:例えば

char *p = "string literal"; 

...だけリテラル文字列を指すようにポインタを設定します。これは最初のバージョンよりも速いですが、リテラルが変更されてはならないという欠点があります。これは、読み取り専用としてマークされたページに存在する可能性があるためです。文字列の長さを知るには関数を使う必要があるという欠点もあります。sizeof演算子はポインタ変数のサイズを与えるだけであるからです。例:

printf("%u\n",unsigned(sizeof(p))); // Will likely display 4 or 8, depending on 
            // whether this is a 32-bit or 64-bit build 
printf("%u\n",unsigned(strlen(p))); // Will display the correct length of 14, not 
            // including the NUL terminator 

これらの変数は、これらの変数でどのような処理を行うかによって異なります。文字列を変更する必要がない場合は、に変更して、char *const char *に変更します。誤って指定した文字に変更を加えないでください。データを変更する予定がある場合は、以前のアレイベースのバージョンを使用して、初期化後にアレイを変更できるようにします。

+2

2番目の例で 'char const *'を使用する方が実際には賢明ですが、コンパイラは標準で後方互換性のある疣贅のために 'char *'バージョンを受け入れることを義務付けられています。 –

+0

@larsmans、私はより完全にするために私の答えにこの事実を追加しました。ありがとう... –

+1

答えにC++出力の例を追加したことがありますが、OPはそれにラベルを付けました。 –

0

必要なものによって異なります。

char a[] = "string literal"; 

自動記憶寿命可変文字列を作成します。これは合法です:一方

a[0] = 'c'; 

...

char *p = "string literal"; 

がメモリを読み取り専用にするポインタを作成します。宣言は本当にあなたが合法的にどのようなpポイントを変更することはできません

const char *p = "string literal"; 

でなければなりません。

0

最初に配列を宣言して記入します(要素を1つずつ設定し、最後のnullバイトが含まれるまで)。配列は変更できます。

第2はポインタを宣言し、それを定数リテラルに設定して入力します。ポインターを変更することができます(たとえば、他の場所を指すようにすることもできます)が、指し示す定数ストリング(ほとんどのシステムでは読み取り専用セグメントに入れられます)を変更することはできません。

0

1つは指定したデータでいっぱいの配列を与え、2つ目は指定したデータを含むどこかのメモリ(通常は読み取り専用)へのポインタを与えます。

より明確に「あなたは何を得る」の違いを確認するには、これを試してみてください。ここで

#include <stdio.h> 
#include <stdlib.h> 

int main(void) 
{ 
    char a[] = "string literal"; 
    char *b = "string literal"; 

    printf("a is %lu bytes, b is %lu\n", (unsigned long) sizeof a, 
             (unsigned long) sizeof b); 

    return EXIT_SUCCESS; 
} 

は、上記のコードでlive demoです。

関連する問題