2

次の C コードを検討してください。

int main(){  
    int* c;  
    c = (int*)malloc(sizeof(int));  
    c = 0xdeadbeef;  
    free(c);  
    return 0;  
}

以前に malloc されたものではない c を解放しようとしているため、これは segfault になります。私の質問は、malloc したばかりのブロックはどうなりますか? 明らかに c はもうそれを指していないので、使用できませんが、まだ「フリー」リストの一部と見なされていますか、それとも明示的なメモリ リークですか?

4

7 に答える 7

12

漏れです。プログラムが終了すると、OS によって再利用されます。

于 2009-04-10T21:00:07.200 に答える
10

メモリがまだ割り当てられているため、メモリ リークが発生します。他の方法でそれをしたいですか?割り当てたメモリを再利用する必要があることをマシン/コンパイラが知る方法は実際にはありません。これが適切な動作でない場合、コードは確率的に機能し、コードを本当に信頼することはできません。

将来のある時点でそのメモリ ブロックをいつでも再ポイントできるため、自動的に解放すると、あなたの下から敷物が引き出されます。

于 2009-04-10T21:02:50.627 に答える
1

c = 7;に変更すると、そのコードはセグメンテーション違反になりません*c = 7;

于 2009-04-10T21:01:59.193 に答える
1

ええと、この時点で発生する segfault は、以前に割り当てていないメモリを解放しようとしたためではなく、オペレーティング システムが許可していないメモリ アドレスを参照しようとしたために発生します (これがセグメンテーション違反の定義です)。

サンプル コードを valgrind で実行すると、いくつかの実験が行われ、次のような出力が得られます。

    ==6945== 無効な free() / delete / delete[]
    ==6945== 0x402265C: フリー (vg_replace_malloc.c:323)
    ==6945== by 0x80483D5: メイン (bla.c:6)
    ==6945== アドレス 0x7 は、スタック、malloc、または (最近) 解放されていません
    ==6945==
    ==6945== エラーの概要: 1 つのコンテキストから 1 つのエラー (抑制: 1 から 11)
    ==6945== malloc/free: 出口で使用中: 1 ブロックで 4 バイト。
    ==6945== malloc/free: 1 つの割り当て、1 つの解放、4 バイトの割り当て。

したがって、これはメモリ リーク 'pur sang' です。ここで、コードを変更して、解放しようとするポインターが割り当てたポインターの「近く」にあるとします (したがって、オペレーティング システムはユーザーがポインターにアクセスできることを認識し、オペレーティング システムはバイト境界でのメモリ アクセスを許可しません)。次のようにコードを変更するとします。

int main(){  
    int* c;  
    c = (int*)malloc(sizeof(int));  
    c++;
    free(c);  
    return 0;  
}

このアプリケーションを実行すると、セグメンテーション違反 (カーネルによって発行される) が表示されなくなりますが、glibc ( malloc() および free() の所有者) からの警告が表示されます。

    edb@Flying-Spaghetti-Monster:/tmp$ ./a.out
    *** glibc が検出されました *** ./a.out: free(): 無効なポインタ: 0x0804a00c ***
    ... トレースが続きます

したがって、カーネルがそれがあなたに属していることを知っているが、glibcがあなたにそれを渡したのを覚えていないメモリを解放しようとしています。これを valgrind (libc の free()、malloc()、realloc()、... 関数を置き換えて独自にアカウンティングを実行することによって動作する) で実行すると、次の出力が得られます。

    ==6955== 無効な free() / delete / delete[]
    ==6955== 0x402265C: フリー (vg_replace_malloc.c:323)
    ==6955== by 0x80483D2: メイン (bla.c:5)
    ==6955== サイズ 4 のブロックが割り当てられた後、アドレス 0x418a02c は 0 バイトです
    ==6955== 0x4022AB8: malloc (vg_replace_malloc.c:207)
    ==6955== by 0x80483C0: メイン (bla.c:3)
    ==6955==
    ==6955== エラーの概要: 1 つのコンテキストから 1 つのエラー (抑制: 1 から 11)
    ==6955== malloc/free: 出口で使用中: 1 ブロックで 4 バイト。
    ==6955== malloc/free: 1 つの割り当て、1 つの解放、4 バイトの割り当て。
于 2009-04-11T09:23:13.623 に答える
1

malloc() の後cは、メモリ アドレスを保持する変数です。この場合、c割り当てた最初のバイトのメモリ アドレスの値を持ちます。

あなたが言うときc = 7、あなたは「c現在、メモリアドレス '7' を指している」と言っています。この場合、メモリ アドレス "7" はプロセスに割り当てられていないため、free() できません。理論的には、メモリ アドレス "7" (または 0xa73c930bf、または設定したもの) が実際にプロセスに割り当てられた可能性があり、その場合、free() は成功します。

ただし、c の値を変更した後も、メモリは割り当てられたままです。プロセスにはまだメモリとそのデータがあります。ポインタを失っただけです。その記憶がどこから始まるかはわかりません。

これは問題ない状況です。C では、そのメモリ アドレスを指すさまざまな変数が存在する場合があります。そのメモリアドレスを格納する「int*」ではなく、「int」を使用することもできます。C は、その特定のメモリ アドレスを保存したかどうかを追跡しようとしません。これは実際には単なる数値です。追跡しようとすると、C ポインターが提供する柔軟性の一部を失う必要があるため、そうするのは不可能な作業です。

あなたの質問に答えると、c の値を追跡する方法がないため、このプログラムにはメモリ リークがあります。つまり、プログラムで使用できないメモリがあるため、リソースが浪費されているということです。

ただし、プログラムが終了すると、プロセスに割り当てられていたすべてのメモリが解放され、他のプログラムが使用できるようになります。

于 2009-04-10T21:17:22.743 に答える
1

私を怒らせないでください。しかし、あなたの質問のポイントが何なのかはっきりしません。あなたがしていることは明らかに、言語が意図していることと真っ向から対立しています。「たまたま消火器のノズルがガソリンタンクの穴に入ったからといって、車のガソリンタンクに消火液を入れたらどうなるか」と言っているのと同じです。
私はジャークになろうとしているわけではありません。なぜこの特定の質問をするのかはっきりしていません。ポインターの力を利用した無限の一連の質問を思い浮かべて、ポインターを誤って使用し、アプリケーションの障害につながる方法がいくつあるのか疑問に思うことができます。それを行う正しい方法を理解できた場合にのみ、コードが実行することを達成しようとしていることはありますか? それとも、ポインタを追跡し、誤って追跡を失った場合にそのメモリを取り戻すのに役立つ内部メカニズムがあるかどうか疑問に思っていますか? (もしそうなら、その質問は上で答えられました)。

于 2009-04-10T21:28:19.787 に答える
0

->の変換は自動的に行われるため、によって返される値malloc()をキャストする必要がないことに注意してください。void*int*

次のように呼び出しを書き直すこともできます。

c = malloc(sizeof *c);

したがってc、 の型を変更しても、割り当てをまったく書き直す必要はありません。

[編集]

割り当てが成功したことを確認することもお勧めします (つまりc != NULL)。

于 2009-04-10T21:08:29.100 に答える