11

他の言語からCへの初心者であり、 http://c.learncodethehardway.org/book/learn-c-the-hard-way.htmlから学習しています。

struct Person {
    char *name;
    int age;
    int height;
    int weight;
};

struct Person *Person_create(char *name, int age, int height, int weight)
{
    struct Person *who = malloc(sizeof(struct Person));
    assert(who != NULL);

    who->name = strdup(name);
    who->age = age;
    who->height = height;
    who->weight = weight;

    return who;
}

2 番目の Person_create 関数が struct Person のポインターを返すことを理解しています。私はそれを理解していません(他の言語、erlang、rubyから来た可能性があります)、なぜそれを次のように定義するのですか

struct Person *Person_create(char *name, int age, int height, int weight)

いいえ

struct Person Person_create(char *name, int age, int height, int weight)

構造体を返す関数を定義する他の方法はありますか?

この質問が基本的すぎる場合は申し訳ありません。

4

5 に答える 5

12

構造体ではなく構造体へのポインターを返すため、そのように定義されています。戻り値をstruct Person *ではなく に割り当てstruct Personます。

次のように、完全な構造体を返すことができます。

struct Person Person_create(char *name, int age, int height, int weight)
{
    struct Person who;
    who.name = strdup(name);
    who.age = age;
    who.height = height;
    who.weight = weight;
    return who;
}

しかし、あまり頻繁には使用されません。

于 2012-05-04T15:52:22.767 に答える
4

このPerson_create関数は a へのポインタを返すstruct Personため、(* を追加して) 戻り値をポインタとして定義する必要があります。構造体自体ではなく構造体へのポインタを返す理由を理解するには、C がメモリを処理する方法を理解する必要があります。

C で関数を呼び出すと、その関数のレコードがコール スタックに追加されます。コール スタックの一番下はmain実行中のプログラムの関数で、一番上は現在実行中の関数です。スタック上のレコードには、関数に渡されたパラメーターの値や関数のすべてのローカル変数などの情報が含まれています。

プログラムがアクセスできる別のタイプのメモリがあります: ヒープメモリです。これは、 を使用してスペースを割り当てる場所でありmalloc、コール スタックには接続されていません。

関数から戻ると、コール スタックがポップされ、関数呼び出しに関連するすべての情報が失われます。構造体を返したい場合は、2 つのオプションがあります。コール スタックからポップされる前に構造体内のデータをコピーするか、データをヒープ メモリに保持して、それへのポインターを返します。単純にポインターを返すよりも、バイトごとにデータをコピーする方がコストがかかるため、通常はリソース (メモリーと CPU サイクルの両方) を節約するためにコピーする必要があります。ただし、費用がかからないわけではありません。freeデータをヒープメモリに保持する場合、使用をやめたときにそれを覚えておく必要があります。そうしないと、プログラムでメモリリークが発生します。

于 2012-05-04T17:10:38.417 に答える
3

この関数は、構造体へのポインタwhoである を返します。struct Person *構造体を保持するメモリは によって割り当てられmalloc()、関数はそのメモリへのポインタを返します。

関数がポインターではstruct Personなく戻りwho値として宣言されている場合は、構造体として宣言することもできます。戻ると、構造体がコピーされ、呼び出し元に返されます。コピーは、単にポインタをメモリに返すよりも効率が悪いことに注意してください。

于 2012-05-04T15:52:32.623 に答える
2

構造体は、C/C++ ではデフォルトでポインター (または参照) ではありません。たとえば、Java の場合と同様です。したがって、Struct Person Function() は、ポインターではなく、構造体自体を (値によって、コピーを作成して) 返します。

オブジェクトのコピー (デフォルトでは浅いコピー、またはコピー コンストラクターを使用して作成されたコピー) を作成したくないことがよくあります。

于 2012-05-04T15:52:53.860 に答える
1

sizeof通常、ポインターは構造体全体よりもはるかに小さいため、ポインターだけでなく構造体全体をコピーすることは効率的ではありませんsizeof

また、構造体にはメモリ内の他のデータへのポインターが含まれている可能性があり、動的に割り当てられたデータにとって危険な可能性がある盲目的にコピーする可能性があります (一方のコピーを処理するコードがそれを解放すると、もう一方のコピーには無効なポインターが残ります)。

したがって、元のコピーがスコープ外になることが確実でない限り、ほとんどの場合、浅いコピーは悪い考えです-そして、代わりに構造体へのポインターを返さないのはなぜですか(もちろんヒープに動的に割り当てられた構造体なので、関数からの戻り時に、スタックに割り当てられたエンティティが破棄されるように破棄されることはありません)。

于 2012-05-04T16:31:01.530 に答える