3

win32 API を使用して C でアプリを作成しています。HeapRealloc() 関数を使用して配列のサイズを拡大しようとすると、配列内の現在の値がコピーされずに変更されます。メモリを再割り当てするために使用するコード:

BOOL ChangeFeedArraySize(UINT newSize)
{   
    char tempChar[20] = "";
    PFEED tempArr;
    if (newSize == 1)
    {
        tempArr = (PFEED)HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(FEED));
    }
    else
    {
        tempArr = (PFEED)HeapReAlloc(heap, HEAP_ZERO_MEMORY, categoryArray, newSize * sizeof(FEED));
        // FEED - a struct
        // PFEED - a pointer to the struct
        // categoryArray - array to be reallocated
    }

    if (tempArr != NULL)
    {
        MessageBox(NULL, ltoa(HeapSize(heap, 0, tempArr),tempChar,10) , "Heap size after reallocation", MB_OK | MB_ICONEXCLAMATION);
        feedArray = tempArr;
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

ブレークポイントにあるときの配列のステータスを次に示します。フィード配列は、現在の配列の状態を示します。一時配列は、新しい再割り当てされた配列の状態を示します (これは異なります)。

フィード配列:

feedArray http://www.freeimagehosting.net/uploads/526b0b2172.jpg

一時配列:

tempArray http://www.freeimagehosting.net/uploads/17858f2e7e.jpg

助けてください.. :\

MSDNの関数説明へのリンク

4

4 に答える 4

6

realloc()あなたはWindows固有の関数を引用していますが、これは標準の同等物である にも当てはまります。

これらの関数が渡されたものと同じアドレスを返す場合は、最初に要求したバッファの直後のメモリが使用されていないためです。したがって、バッファを移動せずに要求を満たすことができます。

しかし、たとえば、すぐに連続して 2 つの迅速な割り当てがあった場合はどうなるでしょうか。最初に要求された直後のメモリが、次の割り当てに使用されてしまった可能性があります。その場合、アロケーターは別の場所にスペースを見つけ、古いバッファーにあったものをコピーし、古いバッファーを解放して、新しいバッファーを返す必要があります。

一般に、この種のことに従う必要があるパターンは次のようなものです。

void *newmem = realloc(oldmem, newsize);
if (!newmem)
{
   // TODO: handle failure
   // possibly free(oldmem); depending on how you want to handle errors
}
else
{
   oldmem = newmem;
}

人々が取る一般的なショートカットは " " ですが、これは障害が発生したときにoldmem = realloc(oldmem, newsize);リークするため、上記ほど優雅ではありません。oldmem

編集に基づいて更新します

あなたのコードで私が疑問に思っていることの1つは、この部分です:

if (newSize == 1)
{
    tempArr = (PFEED)HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(FEED));
}

これは、最初の割り当てが常にサイズ 1 であると想定しているようです。と言うつもりはなかったのですがif (feedArray == NULL)、割り当てnewSize * sizeof(FEED)ますか?

2 回目の更新:

わかった。他に際立っているのはこれです:

    tempArr = (PFEED)HeapReAlloc(ヒープ、HEAP_ZERO_MEMORY、categoryArray、
                                 newSize * sizeof(FEED));
    // をちょきちょきと切る...

    if (tempArr != NULL)
    {
        // をちょきちょきと切る...
        feedArray = tempArr;

太字の部分は同じはずです。

于 2009-11-19T19:00:42.933 に答える
2

HeapReAllocの呼び出し後、元のcategoryArrayが解放されたため、所有しなくなりました。他の割り当てでは、他の目的で再利用され、コンテンツが変更された可能性があります。今後はtempArrを使用する必要があります。

tempArr = (PFEED)HeapReAlloc(heap, HEAP_ZERO_MEMORY, categoryArray, newSize * sizeof(FEED)); 
cetagoryArray = tempArr;
于 2009-11-19T18:54:38.097 に答える
2

ドキュメントから、次のことがわかります。

HeapReAlloc は、新しいメモリが別の場所に割り当てられた場合でも、再割り当てされるメモリの内容を保持することが保証されています。メモリの内容を保存するプロセスには、非常に時間がかかる可能性があるメモリ コピー操作が含まれます。

では、次の質問は、配列の内容が変更されたという結論にどのように到達するかということです。コードを提供していただけますか?関連するポインターの問題や、既存のポインターが現在指している場所に関する仮定が存在する可能性があります (オペレーティング システムの呼び出しが正しいと仮定し、最初にアプリケーション コードに問題がある可能性を完全に排除することが重要です。バグはオペレーティング システム コールに存在する可能性があり、これと同じくらい重要な機能のバグは以前に発見された可能性があります)。

于 2009-11-19T18:46:14.257 に答える
0

HeapRealloc への呼び出し後、どこを見ていますか? 呼び出し後に解放された元のポインタではなく、RETURNEDポインタを調べる必要があります。

于 2009-11-19T19:03:10.837 に答える