8

私が見たガイドは、これを非常によく説明しているようには見えません。

つまり、メモリを a に割り当てるか、代わりにchar*書き込むことができますか? char[25]違いは何ですか?そして、操作できないリテラルがありますか? 固定文字列を変数に代入したい場合はどうしますか? のようにstringVariable = "thisIsALiteral"、その後、どのように操作しますか?

誰かがここで記録を正すことができますか? 最後のケースでは、リテラルを使用して、ヌル終了をどのように処理しますか? これは非常に紛らわしいと思います。


編集: 本当の問題は、私が理解しているように、単純なことを達成するために、これらの異なる構造をうまく使いこなさなければならないことです。たとえばchar *、引数または戻り値としてのみ渡すことができますがchar[]、リテラルを割り当てて変更することしかできません。頻繁に/常に両方を行う必要があることは明らかだと思いますが、それが私の落とし穴です。

4

3 に答える 3

13

char*割り当てられたとの違いは何char[25]ですか?

-ed文字列の有効期間はmalloc、その宣言の範囲によって制限されません。malloc平易な言語では、関数から-ed文字列を返すことができます。自動ストレージchar[25]に割り当てられたものと同じことを行うことはできません。これは、関数から戻ったときにそのメモリが再利用されるためです。

リテラルを操作できますか?

文字列リテラルは読み取り専用ストレージに割り当てられているため、その場で操作することはできません。それらを操作するには、静的、自動、動的などの変更可能なスペースにコピーする必要があります。これはできません:

char *str = "hello";
str[0] = 'H'; // <<== WRONG! This is undefined behavior.

これは機能します:

char str[] = "hello";
str[0] = 'H'; // <<=== This is OK

これも機能します:

char *str = malloc(6);
strcpy(str, "hello");
str[0] = 'H'; // <<=== This is OK too

文字列リテラルのnull終了をどのように処理しますか?

Cコンパイラがnullの終了を処理します。すべての文字列リテラルの最後に、で埋められた余分な文字があり\0ます。

于 2012-10-04T00:54:42.977 に答える
8

あなたの質問は、Cの3つの異なる構造、char配列、ヒープに割り当てられたcharポインター、および文字列リテラルについて言及しています。これらはすべて異なり、微妙な方法です。

  • 関数内でメモリがスタックに割り当てられていることを宣言することで得られるChar配列は、宣言しchar foo[25]たスコープ内にのみ存在しますが、正確に25バイトが割り当てられています。これらのバイトには必要なものを格納できますが、文字列が必要な場合は、最後のバイトを使用してnullで終了することを忘れないでください。

  • で定義された文字ポインタはchar *bar、割り当てられていないメモリへのポインタのみを保持します。bar = fooそれらを利用するには、前のように配列( )またはスペースを割り当てるかのいずれかでそれらを指す必要がありますbar = malloc(sizeof(char) * 25);。後者を行う場合は、最終的にスペースを解放する必要があります。

  • 文字列リテラルは、使用方法によって動作が異なります。それらを使用してchar配列を初期化する場合char s[] = "String";は、その文字列(およびnullターミネータ)を正確に保持するのに十分な大きさの配列を宣言し、その文字列をそこに配置するだけです。これは、char配列を宣言してからそれを埋めるのと同じです。

    一方、文字列リテラルをに割り当てる場合char *、ポインタは変更する必要のないメモリを指しています。変更しようとすると、クラッシュする場合としない場合があり、未定義の動作が発生します。つまり、変更しないでください。

于 2012-10-04T01:00:59.580 に答える
5

他の側面はすでに回答されているので、「char *を使用して関数を渡す柔軟性が必要で、char[]の変更可能性が必要な場合はどうなるか」という質問に追加するだけです。

配列を割り当てて、同じ配列をchar*として関数に渡すことができます。これは参照渡しと呼ばれ、全体をコピーするのではなく、実際の配列のアドレス(正確には最初の要素のアドレス)のみを内部的に渡します。もう1つの効果は、関数内で行われた変更によって元の配列が変更されることです。

void fun(char *a) {
   a[0] = 'y'; // changes hello to yello
}

main() {
   char arr[6] = "hello"; // Note that its not char * arr
   fun(arr); // arr now contains yello
}

mallocで割り当てられたアレイに対しても同じことができます。

char * arr = malloc(6);
strcpy(arr, "hello");

fun(arr); // note that fun remains same.

後でmallocメモリを解放できます

free(arr);

char * aは、アドレスを格納できる単なるポインタであり、単一の変数である場合もあれば、配列の最初の要素である場合もあります。実際に使用する前に、このポインタに割り当てる必要があることに注意してください。

そのcharとは対照的に、arr [SIZE]はスタック上に配列を作成します。つまり、SIZEバイトも割り当てます。したがって、問題なくarr [3]に直接アクセスできます(3がSIZE未満であると想定)。

ここで、任意のアドレスをaに割り当てることを許可しますが、arrにこれを許可しないことは理にかなっています。これは、arrを使用してそのメモリにアクセスする以外に方法がないためです。

于 2012-10-04T05:18:11.657 に答える