0

C の free() 関数の動作について一般的な質問があります。

それを呼び出すfree()と、ポインターが指すメモリが解放されるだけで、ポインターはそのままになると思いますか?

つまり、ポインターを再利用したい場合は、ポインターを再初期化する必要はなく、メモリを再割り当てするだけで済みますか?

たとえば、このコードは合法でしょうか?

元のバージョン

void foo()
{
    data_t *x;
    int y = 0;

    while(x->data != some_value)
    {
        x = some_function(y);
        y = some_other_function(x);
        free(x);
    }
}

修正版

void foo()
{
    data_t *x;
    int y = 0;

    x = some_function(y);

    while(x->data != some_value)
    {
        y = some_other_function(x);
        free(x);
        x = some_function(y);
    }
}

実際のコード (および の内部構造) を無視し、適切にsdata_tと仮定します。これがメモリを管理する適切な方法であるかどうかを知りたいだけですか、それとも解放するたびに再初期化する必要がありますか?some_function()malloc()xdata_t *x

編集:コードが私の質問を適切に示していないことに気付いたので、コードを編集しました。

4

5 に答える 5

2

解放xしてから次のwhileチェックに進むと、未定義の動作が発生します。

次のwhileチェックでは、あなたが作成while(x->data != some_value)し、 x はすでに解放されているためです

次のチェックxを行う前に、次の値に代入する必要がありますwhile

ところで: (最初のチェックで) while の開始時でも、 while ループの前にメモリ領域に開始されないため、未定義の動作があります。x


質問編集に基づいて

free(x)新しいケースの は効果がありません。

xポインタを解放xすると、xが指していた古いメモリアドレスが保持されますが、メモリは割り当てられなくなり、解放されます。

解放後に新しい割り当てられたメモリをxに割り当てると、xは新しいメモリ領域を指します

于 2013-10-10T06:35:47.433 に答える
1

ISO C 標準の抽象言語定義によるとfree、アロケーターから渡された有効な null 以外のポインターを呼び出した後、そのポインターの値はindeterminateになります。その値を使用すると、未定義の動作になります。不確定な値は再び有効になることはありません。

C の実際の実装では、プログラム内に残っている不確定なポインター値が渡され、検出されずに評価される可能性があり、メモリが新しく割り当てられたオブジェクトに再利用されると、それらは有効なポインターと区別できなくなり、さまざまな問題が発生します。

どんな動作も未定義の動作の傘下にあるため、これは仕様に違反しません。

確実に動作するが、メモリ割り当てによって復活するダングリング ポインターに依存するプログラムを作成する場合、そのプログラムは ISO C に従って適切に定義されておらず、コンパイラやオペレーティング システムに従って適切に定義されている可能性は低いです。システムのドキュメント、どちらか。

コンパイルされたプログラムは今日は機能しますが、明日には malloc コードlibc.soが更新されるため、メモリが別の方法で再利用され、プログラムが壊れます。

プログラムが期待どおりの動作をするかどうかをテストすることは重要ですが、それがすべてではありません。また、動作は、言語仕様、システムおよびツールのドキュメントからの何らかの保証に依存する必要があります。そうでない場合は、プログラムの正しい機能について責任を負うことを可能にする何らかの合理的な推論に依存する必要があります。

後者の例としては、言語レベルで C コンパイラを悪用して、目的のマシン コードを取得できる場合があります。これは ISO C では定義されておらず、おそらくコンパイラの開発者によっても定義されていませんが、マシン コードを取得すると、ある意味で、それをどのように取得したかは問題になりません。必要な動作をするかどうかを個別に確認できます。あなたはそれに対して責任を負い、そのコードを監視して不要な変更を監視する回帰セーフガードを配置することができます (コンパイラの操作が異なる場合、またはアップグレードされた場合など)。

mallocおよびの動作に対してこの種の責任を負うことは容易ではありませんfree。これらは実行時のブラックボックスであり、プログラムがデプロイされてから長い時間が経過すると、フィールドで動作が変化する可能性があります。

于 2013-10-10T07:25:16.310 に答える
1

ポインターが指すメモリを解放するだけで、ポインターはそのまま残しますか?

そうです。free() がそれ以外の場合は通常の C 関数である場合、渡すポインター値に影響を与える方法はありません。C は引数を値で渡すため、free() は渡されたポインターのコピーを受け取り、元の x ポインターを変更することはできません。(もちろん、 x が指すものを変更できます

つまり、ポインターを再利用したい場合は、ポインターを再初期化する必要はなく、メモリを再割り当てするだけで済みますか?

free(x);
x = some_function(y);

それがまさにここで行うことです。x を別のものに代入するので、これが通常行うことです。ポインタにはアドレスが含まれており、別のアドレスを割り当てます。

これは、次と同じ概念です。

 int x 
 x = function_that_returns_int();
 x = function_that_returns_int();

に新しい値を割り当てるだけの場合、新しい値を割り当てる前にi他に何もする必要はありませんi

于 2013-10-10T07:18:27.483 に答える