2

明らかに壊れていないので、おそらく少しばかげているように思えることを尋ねて申し訳ありませんが、Cが文字列リテラルをどのように処理するかについての私の(初心者の)理解は、これが機能しないことを示しています...

char some_array_of_strings[3][200];
strcpy(some_array_of_strings[2], "Some garbage");
strcpy(some_array_of_strings[2], "Some other garbage");

C では文字列リテラルを直接変更できないと考えていたため、文字列を処理するときにポインターが使用されていました。これが機能するという事実は、私が何かを誤解していることを示しています。

また、これが機能する場合、なぜ...

some_array_of_strings[1]="Some garbage"
some_array_of_strings[1]="Some garbage that causes a compiler error due to reassignment"

うまくいかない?

4

5 に答える 5

4

「文字列の配列」というフレーズには注意してください。「文字列」はCのデータ型ではありません。それはデータレイアウトです。具体的には、文字列は次のように定義されます。

最初の null 文字で終了し、最初の null 文字を含む連続した文字列

の配列には文字列char含まれる場合があり、char*ポインターは文字列(の最初の文字)を指す場合があります。(標準では、文字列の最初の文字へのポインターを string へのポインターとして定義しています。)

char some_array_of_strings[3][200];

これは、各要素が の 200 要素配列である 3 要素配列を定義しますchar。(これは 2 次元配列であり、C では単に配列の配列です。)

strcpy(some_array_of_strings[2], "Some garbage");

文字列リテラル"Some garbage"は、静的に割り当てられた無名のchar;の配列を参照します。プログラムの実行全体にわたって存在し、変更することはできません。このstrcpy()呼び出しは、その名前が示すように、その配列の内容を、終端のnull 文字までを含めて にコピーします。'\0'some_array_of_strings[]

strcpy(some_array_of_strings[2], "Some other garbage");

同じこと: これは内容"Some other garbage"some_array_of_strings[2]にコピーし、前の行でコピーしたものを上書きします。どちらの場合も、十分なスペースがあります。

文字列リテラルを変更するのではなく、文字列リテラル (より正確には、上記の無名配列) からバイトをコピーして独自の配列を変更しています。

some_array_of_strings[1]="Some garbage";

これは単に「機能しない」だけでなく、違法です。C には配列の代入はありません。

もっと簡単な例を見てみましょう:

char arr[10];
arr = "hello"; /* also illegal */

arr配列型のオブジェクトです。ほとんどのコンテキストでは、配列型の式は、配列オブジェクトの最初の要素へのポインターに暗黙的に変換されます。arrこれは、オブジェクト名と文字列リテラルの代入の両側に適用されます"hello"

しかし、左側のポインターは単なるポインターです。ポインター オブジェクトはありません。技術的に言えば、これはlvalueではないため、割り当ての左側には記述できません42 = x;)。

(配列からポインターへの変換が行われなかったとしても、C では配列の代入が許可されていないため、依然として不正です。)

割り当ての左側にある配列の問題に関する詳細:

配列式がポインターに分解されないコンテキストは、配列式が次の場合です。

  • 単項演算子のオペランドsizeof
  • &単項(address-of) 演算子のオペランド。また
  • 配列オブジェクトを初期化するために使用される初期化子の文字列リテラル。

割り当ての左側は、これらのコンテキストのいずれでもないため、次のようになります。

char array[10];
array = "hello";

LHS は原則としてポインターに変換されます。しかし、結果のポインター式は左辺値ではなくなり、割り当てが制約違反になります。

これを見る 1 つの方法は、式arrayがポインターに変換され、代入が不正になることです。もう 1 つは、代入が不正であるため、プログラム全体が有効な C ではないため、動作が定義されておらず、変換が行われるか行われないかを尋ねても意味がないということです。

(私は「違法」という言葉を少し早口でゆるく使っていますが、この回答はすでに十分に長いので、ここには入りません。)

推奨される読み物: comp.lang.c FAQのセクション 6 。これは、C における配列とポインターの間のしばしば戸惑う関係を説明する優れた仕事をしています。

于 2013-03-28T02:38:38.940 に答える
3

文字列リテラルを変更しているのではなく、それをソースとして使用して文字の配列にコピーしています。コピーが完了すると、文字列リテラルは配列内のコピーとは関係ありません。その後、配列を自由に操作できます。

于 2013-03-28T02:23:00.440 に答える
1
some_array_of_strings[1]="Some garbage"
some_array_of_strings[1]="Some garbage that causes a compiler error due to reassignment"

最初の行では、some_array_of_strings[1] を文字列リテラルに割り当てて、some_array_of_strings[1] または &some_array_of_strings[1] のアドレスが文字列リテラルを指すようにします。したがって、2 行目で some_array_of_strings[1] を再割り当てしようとすると、エラーが発生します。

キースとフレッドが言ったように、strcpy を使用すると、文字列リテラルの文字を配列にコピーするだけです。

于 2013-03-28T02:29:56.013 に答える
1

あなたの定義から、それが 3 つの要素の であるchar some_array_of_strings[3][200];ことを示します。各要素は、それ自体が 200 文字または長さ文字の文字列です。some_array_of_stringsarrayarray200

strcpy(some_array_of_strings[2], "Some garbage");
strcpy(some_array_of_strings[2], "Some other garbage");

これらの 2 つのステートメントでは、実際には有効なコンテンツを一方から他方にコピーしています。は実際には に似ています は に似ていますchar pointerchar pointersome_array_of_strings[2]char[200]char *

some_array_of_strings[1]="Some garbage";
some_array_of_strings[1]="Some garbage that causes a compiler error due to reassignment";

ここでは、サポートされていないieにlikeを割り当てています。違いは内容にあります。char *"Some garbage"char[200]some_array_of_strings[1]assigningcopying

于 2013-03-28T02:29:09.827 に答える
1

some_array_of_strings[2]200 文字の配列です。

ほとんどの式で使用されると、配列の最初の要素へのポインターに「崩壊」します (変換のための派手な言葉)。

strcpy(some_array_of_strings[2], "Some garbage");"Some garbage"次に、配列の最初の要素へのポインターを使用して、1つずつ進めることにより、1文字ずつ200文字の配列にコピーします。

ほとんどの式"Some garbage"では、それぞれの文字と文字列終了文字 ( ) を含む char の配列へのポインタ'\0'です。

some_array_of_strings[1]="Some garbage"一方、200文字の最初の要素への定数/変更不可能なポインターに(文字列への)ポインターを割り当てようとしますが、これも違法です(のように1=2;

于 2013-03-28T02:36:16.923 に答える