为什么Win32 HeapReAlloc()会改变值?

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;
    }
}

以下是调试时数组的状态。 feed数组显示当前数组状态。 temp数组显示重新分配后的新数组状态(不同于原来的数组)。
feed数组: feedArray http://www.freeimagehosting.net/uploads/526b0b2172.jpg temp数组: tempArray http://www.freeimagehosting.net/uploads/17858f2e7e.jpg 请帮忙.. :\
函数描述链接在MSDN

我似乎误导了你,所以我添加了完整的相关代码,并附加了截图。谢谢大家的回复 :) - idcman
4个回答

6

你引用了一个 Windows 特定的函数,但同样适用于标准等效函数 realloc()

如果这些函数返回与传入的相同的地址,则说明你所请求的缓冲区后面的内存是未使用的,因此可以满足请求而不必移动缓冲区。

但如果有两个快速分配紧随其后呢?比如说,原本请求的内存后面的内存被用于下一个分配。在这种情况下,分配器需要在其他地方找到空间,复制旧缓冲区中的内容,释放旧缓冲区,并返回新缓冲区。

通常,你在这种情况下想要遵循的模式如下:

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
根据您的编辑更新:
我对您的代码有一个疑问,就是这部分内容:
if (newSize == 1)
{
    tempArr = (PFEED)HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(FEED));
}

这似乎假定第一次分配的大小总是为1。你确定你没有想说如果(feedArray == NULL),那么就分配newSize * sizeof(FEED)吗?
第二次更新:
好的,另外一个引人注目的地方是这个:
tempArr = (PFEED)HeapReAlloc(heap, HEAP_ZERO_MEMORY, categoryArray, newSize * sizeof(FEED)); // 省略...
if (tempArr != NULL) { // 省略... feedArray = tempArr;
加粗的部分应该相同。

不,我非常确定.. 只有在第一次调用时,newSize等于1。 重新分配后,数组会损坏,就像我在截图中展示的那样... - idcman
第二次更新:不明白你的意思 :
我正在检查分配的内存是否为NULL,如果不是,我就开始将其用作我的永久数组。 再次感谢。
- idcman
刚意识到我真是个蠢货!非常感谢!我混淆了两个相似的函数。 - idcman

2
在调用 HeapReAlloc 后,原始的 categoryArray 已被释放,因此您不再拥有它。其他分配可能已经重用它以用于其他目的,并且内容可能已更改。从现在开始,您需要使用 tempArr:
tempArr = (PFEED)HeapReAlloc(heap, HEAP_ZERO_MEMORY, categoryArray, newSize * sizeof(FEED)); 
cetagoryArray = tempArr;

2
从文档中可以看到:
即使新的内存分配在不同的位置,HeapReAlloc保证保留正在重新分配的内存内容。保留内存内容的过程涉及一次可能非常耗时的内存复制操作。
所以接下来的问题是,你如何得出数组内容已经改变的结论?你能提供代码吗?可能存在指针问题和/或对现有指针指向位置的假设(重要的是首先假定操作系统调用是正确的,并彻底排除应用程序代码的任何可能性,因为虽然操作系统调用可能存在错误,但像这样重要的函数的错误很可能在之前就被注意到了)。

0

在调用HeapRealloc后,你应该查看返回的指针,而不是在你调用之后被释放的原始指针。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接