任意のサイズのファイルから行を読み取る関数を備えた単純なライブラリファイルを作成しました。この関数は、スタックに割り当てられたバッファーとサイズを渡すことによって呼び出されますが、行が大きすぎる場合は、特別なヒープに割り当てられたバッファーが初期化され、より大きな行を返すために使用されます。
このヒープ割り当てバッファは、関数スコープで静的と宣言され、もちろん最初にNULLに初期化されます。関数の先頭に、ヒープバッファがnullでないかどうかを確認するためのチェックをいくつか記述しました。この場合、前の行の読み取りが長すぎました。当然、ヒープバッファを解放し、NULLに戻します。次の読み取りでは、スタックに割り当てられたバッファを埋めるだけでよいと考えています(このアプリケーションでも、1MBを超える行が表示されることは非常にまれです)。
私はコードを調べて、注意深く読んだり、いくつかのテストを実行したりして、かなり徹底的にテストしました。私は、次の不変条件が維持されていると合理的に確信しています。
- スタックバッファが必要なすべてである場合、ヒープバッファは関数の戻り時にnullになります(そしてメモリをリークしません)。
- ヒープバッファがnullでない場合、必要だったため、次の関数呼び出しで解放されます(必要に応じて、次の行で再利用される可能性があります)。
しかし、潜在的な問題について考えました。ファイルの最後の行が長すぎる場合、関数はおそらく再度呼び出されないため、ヒープバッファーを解放する方法がわかりません。これは関数です。 -スコープ、結局のところ。
だから私の質問は、理想的には関数を再度呼び出さずに、関数スコープの静的ポインタで動的に割り当てられたメモリを解放するにはどうすればよいですか?(そして理想的には、それをグローバル変数にすることなく!)
リクエストに応じて利用可能なコード。(今はアクセスできません。申し訳ありません。質問が十分に一般的で、必要ないように十分に説明されていることを願っていますが、ぜひその概念を私に非難してください!)
編集:関数の使用法についていくつかメモを追加する必要があると思います。
この特定の関数は、ファイルからシリアルに読み取られ、すぐにPOD構造体にコピーされる行の形式で使用されます(構造体ごとに1行)。これらは、ファイルが読み取られるときにヒープ上に作成され、これらの構造体のそれぞれには、ファイルからの行(のクリーンアップされたバージョン)を含むcharポインターがあります。これらが持続するためには、コピーがすでに発生している必要があります。(これは、多くの回答で提起された大きな反論の1つでした。ああ、いや、行をコピーする必要があります。
マルチスレッドに関しては、私が言ったように、これはシリアルに使用されるように設計されています。いいえ、スレッドセーフではありませんが、私は気にしません。
たくさんのご回答ありがとうございます!時間があればもっとよく読みます。fgets
現在、私は余分なポインターを渡すか、関数を再設計して、 EOFが表示されたときに、代わりに解放ロジックを構築するだけで、ユーザーがそれについて心配する必要がないようにすることに傾倒しています。