web-dev-qa-db-ja.com

関数に割り当てられたメモリは、関数が戻った後も割り当てられたままですか?

以下のコードの場合:(1) "main"は関数 "f1"を呼び出します。 (2)関数 "f1"はいくつかの数値計算を行います。 mallocを使用して「char」の配列を作成し、配列のポインタをメインに返します(配列の割り当てを解除せずに-配列を解放しません)。

このケースに関連する3つの質問があります。(1)関数 "f1"は終了しましたが、割り当てられたchar配列は、メインプログラムが完全に終了するまで割り当てられたままであると思います。つまり、割り当てられたメモリは引き続きメインに属し、他のプロセスは外部からメインにアクセスできません(つまり、干渉しません)。私は正しいですか? (2)プログラムが終了する前に( "f1"に割り当てられている)配列を解放する必要がありますか(またはメインプログラムが終了するとすぐに解放されますか)? (3) 2番目の質問の答えが「はい」の場合、別の関数に割り当てられた配列をどのように解放しますか?

注:純粋なcの境界内にとどまり、c ++に波及したくない。

char *f1 (...) {
    ...
    ...
    char *fTmp = malloc (length1 * sizeof (char));
    char *fData = malloc (length2 * sizeof (char));
    ...
    ...
    free (fTmp);
    return (fData);
}

int main () {
    char *fData = f1 (...);
    ...
    return (0);
}
13
ssd

関数 "f1"は終了しましたが、割り当てられたchar配列は、メインプログラムが完全に終了するまで割り当てられたままです。

本当。動的に割り当てられたメモリは関数とは関係がなく、プロセスに属します。

つまり、割り当てられたメモリはまだメインに属しており、他のプロセスが外部からアクセスすることはできません。私は正しいですか?

メモリはmain()(関数として意図されている)に属していませんが、それ自体を処理します(main()は単なるエントリポイントです)。メモリ保護を備えたシステム(各プロセスが他のプロセスから分離されている)では、外部からアクセスできません。ただし、システム固有の方法で割り当てて、プロセス間でメモリを共有することはできます。

プログラムが終了する前に( "f1"に割り当てられている)配列を解放する必要がありますか(またはメインプログラムが終了するとすぐに解放されますか)

はい。未割り当てのメモリ-ほとんどのシステムで-プロセスが終了すると、オペレーティングシステムによって自動的に割り当てが解除されますが、これはシステムによって異なります。 IMOは、OSがそれを行う場合でも、レッドフラグなどの自動割り当て解除を使用して、常に割り当てを解除する必要があります(割り当て解除することを忘れていますが、バグですか?見逃したものですか?)。さらに、_f1_が1000回呼び出されると、使用可能なすべてのメモリをすばやく消費するたびにメモリがリークします。サーバーのプロセスについて考えてみてください。それは何年も稼働している可能性があります(またそうでなければなりません)。

2番目の質問の答えが「はい」の場合、別の関数に割り当てられた配列をどのように解放しますか?

誰がメモリを割り当ててそれを解放するのもいいですね。それが不可能な場合、発信者はそのようなメモリの責任を負います。たとえば、strdup()が行うことです。このような場合、呼び出された関数は、割り当てられたメモリ(または別の特殊な関数で使用できるハンドル/トークン)へのポインタを(何らかの方法で)返す必要があります。例えば:

_char* pBuffer = f1();
// Use it
free(pBuffer);
_

このような内部ポインターを非表示にする場合は、多くの手法があることに注意してください。トークン(たとえば、整数、辞書のキー)、typedef、または不透明なタイプを使用できます。

19
Adriano Repetti
  1. はい、malloc()で割り当てられたメモリは、解放されるまで残ります。関数が可変サイズのデータ​​を呼び出し元に返す方法は他にありますか?

  2. プログラムが終了すると、malloc()で割り当てられたすべてのメモリが解放されます。ただし、パフォーマンスに影響を与えたり、システムの仮想メモリが不足したりする可能性があるため、プログラムが終了するまで、不要なメモリを大量に保持することは一般的にはお勧めできません。これは、実行時間の長いプログラムにとって特に問題になる可能性があります。それらのメモリ使用量は、利用可能なすべての仮想メモリを使用するまで増加し続ける場合があります。

  3. 関数から返されたポインタでfree()を呼び出します。したがって、あなたの場合、main()は配列を使用した後にfree(fData)を実行できます。

これはすべて、Cプログラミングクラスまたは教科書でカバーされている必要があります。

6
Barmar

mallocはヒープにメモリを割り当てるため、このメモリはfree関数またはプログラムによって解放されるまで、割り当てられたままになります。
あなたの場合、f1ftempを解放したので、関数が終了した後は存在しなくなりました。 fdataはヒープ上にあり、割り当てられた場所へのポインターを返すため、mainにアクセスできます。

mainが正常に終了すると、fdataが指すメモリが解放されます。

したがって、メモリが不要になったらすぐにメモリを解放することをお勧めします。プロセスが終了すると(最新のオペレーティングシステムを考慮して)、プログラムのすべてのスペースがシステムに戻されるため、プログラムの最後にブロックを解放しても意味がありません。

3
haccks

mallocを使用すると、freeになるまでヒープにメモリが割り当てられます。

これは、すべてのmallocに対応する空きがあることを確認する必要があることを意味します。また、他のプロセスがデータにアクセスできないことを意味するものではありません。これは、アドレスの値にすぎません。

メインでは、メモリリークを回避するためにfree(fData)を実行する必要があります。

要約すると:

1)最初の仮定は正しいですが、2番目と3番目は正しくありません。割り当てられたままになりますが、メインに対してローカルではなく、 終了時にプロセスにバインドされていません

2)はい、あなたはそれを解放しなければなりません

3)関数から取得したポインターを使用します。関数から割り当てられたデータへのポインターを返さない場合は、その関数がそれをfreesすることを確認してください。

1
AlexanderBrevig
  1. はい、まだヒープにあります。ただし、プロセスの概念について混乱しています。 (* nixでforkを使用して)別のプロセスを作成しない限り、それは同じプロセスです。

  2. 使用されていないときにメモリを解放するのは良い習慣です。ただし、プログラムが正常に終了した場合、割り当てられたメモリはシステムによって解放されます。

  3. このような:

    int main () {
        char *fData = f1 (...);
        //...
        free(fData);
        //...
    }
    
1
Yu Hao

Cで使用できるメモリには、基本的に2つのタイプがあります。2つのタイプは、スタックとヒープです。通常、関数内で作成した変数はスタックに割り当てられ、関数が戻ったときに解放されます。ヒープに割り当てられたメモリは存続し、プログラム内でその割り当てを管理する義務があります。ヒープ内のメモリは、データブロックを参照するポインタ(メモリアドレス)を使用して解放されるまで割り当てられたままになります。

両方を少し読むと、理解するのに役立ちます。 fDataのインスタンスが2つあり、それぞれに独自のスコープがあることを指摘しておきます。両方のポインタは、割り当てるメモリを指します。

char *fData = malloc (length2 * sizeof (char));

..コードの実行時にスコープ内外を通過する場合でも。

1
Perry Horwich

使用していないメモリを解放しないと、最終的にこれが蓄積され(他の多くのポインタを使用してこれを実行した場合)、プログラムのメモリが不足する可能性があります。 free関数を使用してメモリブロックを解放した後、ポインターにNULLを割り当てることをお勧めします。その場合、未定義の動作が発生する可能性がありますが、NULLポインターへのアクセスと操作はクラッシュを引き起こすため、問題を簡単に追跡できます

1
83457