6

私が理解しているように、より大きなメモリブロックを予約するように求められると、realloc()関数は次の3つの異なることのいずれかを実行します。

if free contiguous block exists
    grow current block
else if sufficient memory
    allocate new memory
    copy old memory to new
    free old memory
else
    return null

現在のブロックを拡張するのは非常に安価な操作なので、これを利用したい動作です。ただし、(たとえば)既存の文字列の先頭にcharを挿入したいためにメモリを再割り当てしている場合は、realloc()にメモリをコピーさせたくありません。最終的には、realloc()を使用して文字列全体をコピーしてから、手動で再度コピーして、最初の配列要素を解放します。

realloc()が何をするかを決定することは可能ですか?もしそうなら、クロスプラットフォームの方法で達成することは可能ですか?

4

8 に答える 8

7

realloc()の動作は、特定の実装に依存している可能性があります。そして、それに基づいてコードを作成することは、控えめに言っても、カプセル化に違反するひどいハックになります。

特定の例のより良い解決策は次のとおりです。

  1. 現在のバッファのサイズを見つける
    • malloc()以前のバッファよりも大きい新しいバッファ(を使用)を割り当てます
    • 必要なプレフィックスを新しいバッファにコピーします
    • プレフィックスの後に開始して、前のバッファの文字列を新しいバッファにコピーします
    • 前のバッファを解放します
于 2008-10-19T14:08:53.350 に答える
2

コメントに記載されているように、質問のケース 3 (メモリなし) は間違っています。realloc()利用可能なメモリがない場合は NULL を返します [質問は修正されました]。

realloc()「Code Complete」の Steve McConnell は、失敗したときに元のポインターの唯一のコピーに戻り値を保存すると、realloc()メモリ リークが発生しただけだと指摘しています。あれは:

void *ptr = malloc(1024);
...
if ((ptr = realloc(ptr, 2048)) == 0)
{
    /* Oops - cannot free original memory allocation any more! */
}

realloc() の実装が異なれば、動作も異なります。想定する唯一の安全なことは、データが常に移動されるということです。つまり、メモリを realloc() すると常に新しいアドレスが取得されるということです。

他の誰かが指摘したように、これについて心配している場合は、アルゴリズムを検討する時期かもしれません。

于 2008-10-19T14:47:51.680 に答える
1

文字列を後方に保存すると役立ちますか?

そうでなければ...必要以上のスペースをmalloc()して、スペースが足りなくなったら新しいバッファにコピーしてください。簡単な方法は、毎回スペースを 2 倍にすることです。これは、文字列が大きいほど (つまり、新しいバッファへのコピーに時間がかかるほど)、必要な頻度が少なくなるため、非常にうまく機能します。

この方法を使用すると、バッファ内の文字列を右揃えにすることもできるため、先頭に文字を簡単に追加できます。

于 2008-10-28T05:39:18.220 に答える
0

次のように、文字列の左側に空のバッファスペースを保持してみませんか。

char* buf = malloc(1024);
char* start = buf + 1024 - 3;
start[0]='t';
start[1]='o';
start[2]='\0';

文字列の先頭に「on」を追加して「onto\0」にするには:

start-=2;
if(start < buf) 
  DO_MEMORY_STUFF(start, buf);//time to reallocate!
start[0]='o';
start[1]='n';

このように、最初に挿入を行うたびにバッファをコピーし続ける必要はありません。

最初と最後の両方で挿入を行う必要がある場合は、両端にスペースを割り当てるだけです。明らかに、中央に挿入すると、要素をシャッフルする必要があります。

于 2008-10-28T06:04:01.057 に答える
0

いいえ-そしてあなたがそれについて考えるならば、それはうまくいきません。何をするのかを確認してから実際に実行するまでの間に、別のプロセスがメモリを割り当てる可能性があります。 マルチスレッドアプリケーションでは、これは機能しません。何が行われるかを確認してから実際に実行するまでの間に、別のスレッドがメモリを割り当てる可能性があります。

この種のことを心配している場合は、使用しているデータ構造を調べて、そこで問題を修正できるかどうかを確認する時期かもしれません。これらの文字列の作成方法によっては、適切に設計されたバッファーを使用して非常に効率的に作成できます。

于 2008-10-19T13:37:14.570 に答える
0

クロスプラットフォームの方法では不可能だと思います。 これは、プラットフォームに依存する方法でそれを行う方法の手がかりを与える可能性のあるulibc実装のコードです。実際には、glibcソースを見つける方が良いですが、これはgoogle検索の上にありました:)

于 2008-10-19T13:44:49.423 に答える
0

obstackがメモリ割り当てのニーズに適している場合は、急速に成長している機能を使用できます。Obstack は glibc の機能ですが、かなり移植性の高いlibibertyライブラリーでも利用できます。

于 2008-10-19T14:46:45.630 に答える
0

より良いアプローチは、リンクされたリストを使用することです。各データ オブジェクトを 1 つのページに割り当て、別のページを割り当てて、前のページまたはインデックス ページからそのページへのリンクを作成します。これにより、次の割り当てがいつ失敗するかがわかるため、メモリをコピーする必要がなくなります。

于 2010-10-07T03:04:20.603 に答える