1

次のコードがあります。

typedef struct{
    char *name;
    int age;
} person_t;

person_t
read_person(void);

int main(){
    person_t Peter = read_person();
    printf("%s %d\n", Peter.name, Peter.age);
}

person_t
read_person(void) {
    person_t a;
    a.name = "Peter";
    a.age = 18;
    return a;
}

したがって、関数 read_person では、struct person_t が返されます。「a」はローカル変数なので、関数が終了すると配列 a.name が解放されるのだろうか。

プログラムを実行すると、次の行が出力されることがわかりました

Peter 18

つまり、a.name は解放されません。誰かがこれについて説明できますか?

4

6 に答える 6

2

aそこから戻るread_personと、内容のコピーが作成されます。ローカル変数のストレージは、自動変数であるためa、プログラムが終了すると実際に削除されます。read_person

nameはポインターであり、静的な保存期間を持つ文字列リテラルを指します。これは、プログラムの寿命が続くことを意味し、ポインターを編集"Peter"する必要はありません。free文字列リテラルを変更しようとする試みは未定義の動作であるため、 の内容を変更できないことに注意してくださいname

一方、ed メモリnameを指している場合は、 malloced にする必要がありますfree。または、次のようにローカル変数を宣言した場合read_person:

 char arr[] = "Peter" ;

それに割り当てた場合、終了すると存在しなくなるためa、未定義の動作が発生します。arrread_person

于 2013-09-27T13:03:24.960 に答える
1

はいといいえ。ここで見逃しているのは、関数から戻ることによって呼び出される暗黙のコピー操作だと思います。person_t aのスタック フレームに存在することは事実ですread_person()。ただし、return aの値は、代入 ( ) により、スタック フレームに存在aする にメンバごとにコピーされます。コピーが完了した後、 s スタック フレーム内のオブジェクトは実際に解放されます (ただし、再帰的にではありません。あなたが懸念していた と同等のことはしません)。person_t Petermain()Peter = read_person()person_t aread_person()free(a.name)

最適化の設定とコンパイラの使用年数によっては、さらに複雑になりa、一時的な unnamed にコピーされperson_t、それが にコピーされる場合がありPeterます。ただし、多くのコンパイラは余分なコピーを簡単に最適化できます。

実際、それはそれよりも単純である可能性もあります-それがプログラム全体である場合、コンパイラはそれが の唯一の呼び出しであることを認識し、関数を にread_person()選択することができます。その後、さらなる最適化がそれに気づき、その場合、効果的にその場で構築され、...inlinemain()aPeterread_person()Petera

于 2013-09-27T13:21:24.450 に答える
1

まず、name配列ではなく、へのポインタです。char正確には、文字列リテラルを指します"Peter"。また、文字列リテラルには静的ストレージがあり、いつでもアクセスできます。

第二に、これはローカル変数ですが、ポインターではなくaを返しているため、 の値が変数に割り当てられます。でアクセスしても問題ありません。structaPetermain

于 2013-09-27T13:03:20.133 に答える
1

32 ビット マシンを使用していると仮定すると、ポインターと int は両方とも 4 バイトになります。次に、構造体のサイズは 8 バイトです (それ以上になる可能性がありますが、簡略化しています)。

コンパイル時に、6 文字、'P', 'e', 't', 'e', 'r'、および NULL ゼロを保持するのに十分なスペースを持つ場所が静的メモリに確保されます。の場所は、'P'A1 のような住所になります。このデータは静的メモリにあります。

実行時:
最初にスタック メモリmain()に置かれます。 次に、スタック上に 8 バイトが予約されます。これはピーターという名前の変数です。 その後、スタックに置かれます。 次に、別の 8 バイトがスタックに置かれます。これは という名前の変数です。 次に、値 A1 が の最初の 4 バイトに入れられます。 次に、値 18 が の 2 番目の 4 バイトに入れられます。 その後、関数は戻ります。戻り時: のスタックから 8 バイト全体が のスタックにコピーされます。その後、スタックから取り除かれます。 したがって、peter の最初の 4 バイトには値 A1 が含まれます。2 番目の 4 バイトには 18 が含まれます 。

read_person()
a
a
a
apeterread_person

printfステートメントはスタックに置かれますread_person。4 バイトの値 A1 と 4 バイトの値 18 も使用するためprintfにスタックに置かれます。
print ステートメントはそれを実行し、与えられたパラメーターと同様にスタックから取り出されます。
メインが完了し、スタックから取り出され、スタックは再び空になります。

ヒープ メモリから何も割り当てられていないことに注目してください。プログラムはオペレーティング システムに対して、mallocまたは同様の呼び出しを使用して作業するためのヒープ領域を提供するよう要求することはありませんでした。したがって、解放するものは何もありません。

于 2013-09-27T13:17:01.840 に答える