9

C の学習を始めたばかりで、文字列ポインターと文字列 (char の配列) について混乱していることに気付きました。誰かが私の頭を少しすっきりさせるのを手伝ってくれませんか?

// source code
char name[10] = "Apple";
char *name2 = "Orange";

printf("the address of name: %p\n", name);
printf("the address of the first letter of name: %p\n", &(*name));
printf("first letter of name using pointer way: %c\n", *name);
printf("first letter of name using array way: %c\n", name[0]);
printf("---------------------------------------------\n");
printf("the address of name2: %p\n", name2);
printf("the address of the first letter of name2: %p\n", &(*name2));
printf("first letter of name2 using pointer way: %c\n", *name2);
printf("first letter of name2 using array way: %c\n", name2[0]);

// output
the address of name: 0x7fff1ee0ad50
the address of the first letter of name: 0x7fff1ee0ad50
first letter of name using pointer way: A
first letter of name using array way: A
---------------------------------------------
the address of name2: 0x4007b8
the address of the first letter of name2: 0x4007b8
first letter of name2 using pointer way: O
first letter of name2 using array way: O

そのため、name と name2 の両方が自身の最初の文字のアドレスを指していると想定しています。それから私の混乱は(以下のコードを参照)

//code
char *name3; // initialize a char pointer
name3 = "Apple"; // point to the first letter of "Apple", no compile error

char name4[10]; // reserve 10 space in the memory
name4 = "Apple"; // compile errorrrr!!!!!!!!!!

「Apple」の最初の文字への name2 および name2 ポインターと呼ばれる char ポインターを作成します。これで問題ありません。次に、char の別の配列を作成し、メモリに 10 スペースを割り当てます。次に、「Apple」の最初の文字を指すアドレスである name4 を使用してみます。その結果、コンパイルエラーが発生しました。

私はこのプログラミング言語にとてもイライラしています。時々それらは同じように働きます。しかし、そうでない場合もあります。誰でもその理由を説明できますか?また、文字列または文字の配列を別々の行に作成したい場合はどうすればよいですか? どうすればそれができますか???

どうもありがとう...

4

5 に答える 5

9

次のように、配列を宣言するときに配列を初期化できます。

int n[5] = { 0, 1, 2, 3, 4 };
char c[5] = { 'd', 'a', 't', 'a', '\0' };

しかし、通常は char 配列を文字列として扱うため、C では特殊なケースが許可されます。

char c[5] = "data";  // Terminating null character is added.

ただし、配列を宣言すると、それを再割り当てすることはできません。なんで?次のような割り当てを検討してください

char *my_str = "foo";  // Declare and initialize a char pointer.
my_str = "bar";        // Change its value.

最初の行は char ポインターを宣言し、foo. fooは文字列定数であるため、他のすべての定数と共にメモリ内のどこかに常駐します。ポインターを再割り当てすると、新しい値が割り当てられます: のアドレスですbar。しかし、元の文字列fooは変更されません。ポインターを移動しましたが、データは変更していません。

ただし、配列を宣言するときは、ポインターをまったく宣言していません。一定量のメモリを予約して名前を付けています。だからライン

char c[5] = "data";

文字列定数で始まり、data5 つの新しいバイトを割り当て、それらを呼び出しc、文字列をそれらにコピーします。配列の要素へのポインタを宣言した場合とまったく同じように、配列の要素にアクセスできます。配列とポインターは、(ほとんどの目的で) そのように交換可能です。

ただし、配列はポインターではないため、再割り当てすることはできません。

cポインターではないため、他の場所に「ポイント」を作成することはできません。それはメモリ領域の名前です。

一度に 1 文字ずつ、または次のような関数を呼び出して、文字列の値を変更できますstrcpy()

c[3] = 'e';       // Now c = "date", or 'd', 'a', 't', 'e', '\0'
strcpy(c, "hi");  // Now c = 'h', 'i', '\0', 'e', '\0'
strcpy(c, "too long!") // Error: overflows into memory we don't own.

効率のヒント

また、配列を初期化すると、通常はデータのコピーが作成されることにも注意してください。元の文字列は定数領域からデータ領域にコピーされ、プログラムで変更できます。もちろん、これは予想の 2 倍のメモリを使用していることを意味します。代わりにポインターを宣言することで、コピーを回避し、通常はメモリを節約できます。これにより、文字列は定数領域に残り、文字列の長さに関係なく、ポインターに十分なメモリのみが割り当てられます。

于 2013-06-13T00:45:00.060 に答える
2

ポインターと配列はなじみがあるように見えますが、異なるものです。これchar *name3は への単なるポインタでありchar、ポインタより多くのメモリを必要としません。アドレスを格納するだけなので、文字列を割り当てると、格納されname3ているアドレスが のアドレスに変更されます"Apple"

しかし、あなたname4はの配列でありchar[10]、10文字のメモリを保持します。割り当てたい場合は、strcpyまたは何かを使用してメモリに書き込む必要がありますが、のようなアドレスを割り当てないで"Apple"ください。

于 2013-06-13T00:33:15.673 に答える
2

値を配列型 (たとえば、10charの配列name4) に直接再割り当てすることはできません。コンパイラにとっては「配列」であり、代入演算子を使用して文字列リテラルを含む配列に書き込むname4ことはできません。=

文字列「Apple」の内容を、割り当てた 10 バイト配列 ( name4) に実際に移動するには、またはそのようなものを使用する必要がありstrcpy()ます。

あなたがやっていることname3はかなり異なります。として作成され、char *ガベージまたはゼロに初期化されます (この時点ではわかりません)。次に、静的文字列「Apple」の場所を割り当てます。name3これは読み取り専用メモリに存在する文字列であり、ポインタが指すメモリに書き込もうとしても決して成功しません。

これに基づいて、最後のステートメントが静的文字列のメモリ位置を 10 のコレクションを表す別の場所に割り当てようとしていると推測できますchar。言語は、このタスクを実行するための事前に決定された方法を提供しません。

ここにその力があります。

于 2013-06-13T00:31:46.553 に答える
2

あなたが言う時

char *name3 = "Apple";

name3静的文字列を指すことを宣言しています"Apple"。高水準言語に精通している場合は、これを不変と考えることができます (以前にプログラミングしたことがあると思われるため、このコンテキストで説明します。技術的な根拠については、C 標準を確認してください)。

あなたが言う時

char name4[10];
name4 = "Apple";

最初に 10 文字の配列を宣言し (つまり、可変メモリの 10 バイト セクションの先頭を「指している」)、次に不変"Apple"をこの配列に割り当てようとするため、エラーが発生します。後者の場合、実際のデータ割り当てはメモリの読み取り専用セグメントで行われます。

これは、型が一致しないことを意味します。

error: incompatible types when assigning to type 'char[10]' from type 'char *'

name4値が必要な場合は、次"Apple"を使用しますstrcpy

strcpy(name4, "Apple");

name4初期値が必要な場合"Apple"は、それも可能です。

char name4[10] = "Apple"; // shorthand for {'A', 'p', 'p', 'l', 'e', '\0'}

前の例では機能しないのに対し、これが機能する理由"Apple"は、 が a の有効な配列初期化子であるためですchar[]。つまり、10 バイトの char 配列を作成し、その初期値を"Apple"(残りの場所は 0 で) に設定します。

int 配列を考えると、これはより理にかなっています。

int array[3] = {1, 2, 3}; // initialise array

おそらく、私が考えることができる最も簡単な口語的な説明は、配列は物事のバケットのコレクションであるのに対し、静的文字列"Apple"は「そこにある」単一のものであるということです。

strcpy(name4, "Apple")それぞれのもの (文字)"Apple"name41 つずつコピーするため、機能します。

しかし、「このバケツの集まりはあそこのものと同じだ」と言っても意味がありません。バケットを値で「埋める」ことだけが意味があります。

于 2013-06-13T00:32:04.200 に答える