3

K&R 本の 104 ページで、次のステートメントに出くわしました。

char amessage[] = "now is the time"; //an array
char *pmessage = "now is the time";  //a pointer

配列内の個々の文字は変更される場合がありますが、amessage 常に同じストレージを参照します。その後、pmessageポインターは別の場所を指すように変更される可能性がありますが、文字列の内容を変更しようとした場合の結果は未定義です...

それで、これは両方のケースで彼らが意味したエラーでしょうか?

配列については、

amessage[] = "allocate to another address"; //wrong?

ポインタについては、

pmessage[0] = 'n'; //wrong?

これらのルールに違反しているときを知りたいだけです。

ありがとう。

4

5 に答える 5

6
/* OK, modifying an array initialized by the 
 * elements of a string literal */
amessage[0] = 'n';

/* not OK, modifying a string literal.
 * String literals are non-modifiable */
pmessage[0] = 'n';

Cでは配列を割り当てることができないため、配列をコピーする場合は、関数を使用memcpyするか、strcpy関数を使用して文字列をコピーすることに注意してください。

于 2012-07-27T15:53:52.537 に答える
3
char amessage[] = "now is the time";
/*   ^            ^
     (an array)   (a string literal) */

このように文字列リテラルを使用して配列を初期化すると、配列の要素の初期値がリテラル自体の初期値に設定されます。そしてもちろん、配列には独自の個別のメモリが割り当てられます。また、その内容を変更できます。

char *pmessage  = "now is the time";
/*   ^            ^
     (a pointer)  (a string literal) */

文字列リテラルを使用してポインターを初期化すると、ポインターが文字列リテラルを指すようになります。この文字列リテラルは、読み取り専用メモリに格納できます。したがって、変更することはできません。ポインター自体は変更できます。

何が有効で、何が有効でないか?

amessage[0] = 'n'; /* Valid. Modifying array contents.  */
amessage = pmessage; /* Invalid. You cannot assign to an array.  */
pmessage[0] = 'n'; /* Invalid. You're trying to modify a string literal.  */

しかし:

pmessage = amessage; /* Valid. You're modifying a pointer. */

続いて:

pmessage[0] = 'n'; /* Valid. You just modified pmessage above,
                   and it now points to modifiable memory.  */

最後に: まさにこれに関する C-FAQ エントリがあります。一読の価値ありです。

ouahの回答に触発されました。大幅な編集はしたくありませんでした。

于 2012-07-27T16:18:54.300 に答える
3

ポインターが定数データを指していない限り (文字列リテラルが定数データである場合を除き)、ポインターを配列として使用することに本質的に問題はありません。意味的には正しくありませんが、メモリ保護のない昔は、pmessage[0] = 'n';実際には予測できない結果をもたらしていました (たとえば、プログラム内の同じリテラルのすべての出現に影響を与えます)。最新のオペレーティング システムでは、メモリ保護が設定されているため、これは発生しませんでした。文字列リテラルおよびその他の定数は、実行可能ファイルのいわゆる読み取り専用セクションに配置され、プロセスを作成するために実行可能ファイルがメモリにロードされると、読み取り専用セクションを含むメモリ ページが読み取り専用になります。つまり、コンテンツを変更しようとすると、セグメンテーション違反が発生します。

char amessage[] = "now is the time";

実際には、次の構文糖衣です。

char amessage[] = { 'n','o','w',' ','i','s',' ','t',
                    'h','e',' ','t','i','m','e','\0' };

つまり、16 文字の配列を作成し、その内容を文字列 "now is the time" (NULL ターミネータと共に) で初期化します。

一方で

char *pmessage = "now is the time";

同じ文字列データを読み取り専用データのどこかに置き、そのアドレスをポインターに割り当てますpmessage。これは次のように機能します。

// This one is in the global scope so the array is not on the stack
const char _some_unique_name[] = "now is the time";

char *pmessage = _some_unique_name;

_some_unique_nameプログラム内の他の識別子と衝突しないように選択されています。通常、C 言語では許可されていないが、アセンブラとリンカでは使用できる記号が使用されます (例: のようなドットstring.1634)。

ポインターの値を変更することができます。これにより、別の文字列など、別のものを指すようになります。ただし、配列の名前の背後にあるアドレスを変更することはできません。つまりamessage、最初に割り当てられた同じ配列ストレージを常に参照します。

amessage[i]orを使用して各文字列の個々の要素を参照できますが、読み取り/書き込みメモリに配置されているpmessage[i]の要素にのみ割り当てることができます。amessage

于 2012-07-27T16:25:28.410 に答える
1

これを行う場合:

char amessage[] = "now is the time"; //an array
char *pmessage = "now is the time";  //a pointer

あなたはおそらく本当にこれをやりたいと思っています:

const char *pmessage = "now is the time";  //a pointer

プログラムがコンパイルされると、メモリのどこかに「今がその時です」というバイトがあります (NULL ターミネータがあることに注意してください)。これは一定のメモリになります。奇妙なことが起こる可能性がある場合は、それを変更しようとしないでください (正確に何が起こるかは、環境と、読み取り専用または読み取り/書き込みメモリに格納されているかどうかによって異なります)。そのため、K&R はどのようにできるかを説明しようとしましたが、現実的な方法は、定数文字列へのポインターを const にすることです。そうすれば、内容を変更しようとすると、コンパイラーは文句を言います。

于 2012-07-27T16:11:07.347 に答える
1
char amessage[] = "now is the time"; //an array

配列名は定数です。つまり、配列のアドレスは変更できません。ただし、配列の内容は変更できます。

それで

amessage[0]='n';//valid and it change the first element

しかし

amessage="hello";//if you try then it wrong as array address can not be changed

ポインタの部分を見てください:-

char *pmessage = "now is the time";  //a pointer

これはポインタであるため、任意のアドレスを指すことができます。ただし、メモリ内のそのアドレス位置は変更可能である場合と変更できない場合があります。つまり、読み取り専用である場合と、読み取りと書き込みの両方が許可されている場合があります。

そのため、ポインター pmessage を使用してメモリ内のデータを変更しようとすると、メモリの結果が依存するポイントに依存します。ここでは、コード セクションを指しているため、読み取り専用です。

それで

pmessage[0]='n';//definitely give you error
于 2012-07-27T16:22:12.883 に答える