为什么realloc不行而malloc可以呢?
我已经达到了 realloc 停止返回指针的地步 - 我认为缺少空间来扩展或移动数组。唯一的问题是我确实需要内存存在,否则应用程序无法按预期运行,因此我决定尝试 malloc - 期望它不起作用,因为 realloc 不起作用 - 但它确实起作用。为什么?
然后我将指针数组memcpy到新分配的数组中,但发现它破坏了它,像0x10和0x2b这样的指针被放入数组中。有真正的指针,但如果我用 for 循环替换 memcpy,就可以修复它。为什么 memcpy 这样做?我不应该在代码中使用 memcpy 吗?
代码:
float * resizeArray_by(float *array, uint size)
{
float *tmpArray = NULL;
if (!array)
{
tmpArray = (float *)malloc(size);
}
else
{
tmpArray = (float *)realloc((void *)array, size);
}
if (!tmpArray)
{
tmpArray = (float *)malloc(size);
if (tmpArray)
{
//memcpy(tmpArray, array, size - 1);
for (int k = 0; k < size - 1; k++)
{
((float**)tmpArray)[k] = ((float **)array)[k];
}
free(array);
}
}
return tmpArray;
}
void incrementArray_andPosition(float **& array, uint &total, uint &position)
{
uint prevTotal = total;
float *tmpArray = NULL;
position++;
if (position >= total)
{
total = position;
float *tmpArray = resizeArray_by((float *)array, total);
if (tmpArray)
{
array = (float **)tmpArray;
array[position - 1] = NULL;
}
else
{
position--;
total = prevTotal;
}
}
}
void addArray_toArray_atPosition(float *add, uint size, float **& array, uint &total, uint &position)
{
uint prevPosition = position;
incrementArray_andPosition(array, total, position);
if (position != prevPosition)
{
float *tmpArray = NULL;
if (!array[position - 1] || mHasLengthChanged)
{
tmpArray = resizeArray_by(array[position - 1], size);
}
if (tmpArray)
{
memcpy(tmpArray, add, size);
array[position - 1] = tmpArray;
}
}
}
在我完成所有修复之后,代码可能会初始化。这里有趣的是,在对数组进行排序之后,我使用 malloc 分配了一个巨大的数组,以便将数组重新排序为一个数组以用作 GL_ARRAY_BUFFER。如果 realloc 由于空间不足而没有分配,那么为什么没有分配呢?
最后,无论如何,这都会导致它最终崩溃。经过渲染函数一次崩溃后。如果我删除了所有修复并在 realloc 未分配时捕获它会正常工作。这就引出了一个问题,分配我的数组而不是重新分配会导致进一步的问题,这有什么问题吗?
我的数组是浮点指针的指针。当我增长数组时,它会转换为指向浮点的指针并重新分配。我正在 Android 上构建,所以这就是我认为内存不足的原因。
I have reached a point where realloc stops returning a pointer - I assume that there is a lack of space for the array to expand or be moved. The only problem is I really need that memory to exist or the application can't run as expected, so I decided to try malloc - expecting it not work since realloc would no work - but it did. Why?
Then I memcpy the array of pointers into the new allocated array, but found it broke it, pointers like 0x10 and 0x2b was put in the array. There are real pointers, but if I replace the memcpy with a for loop, that fixes it. Why did memcpy do that? Should I not be using memcpy in my code?
Code:
float * resizeArray_by(float *array, uint size)
{
float *tmpArray = NULL;
if (!array)
{
tmpArray = (float *)malloc(size);
}
else
{
tmpArray = (float *)realloc((void *)array, size);
}
if (!tmpArray)
{
tmpArray = (float *)malloc(size);
if (tmpArray)
{
//memcpy(tmpArray, array, size - 1);
for (int k = 0; k < size - 1; k++)
{
((float**)tmpArray)[k] = ((float **)array)[k];
}
free(array);
}
}
return tmpArray;
}
void incrementArray_andPosition(float **& array, uint &total, uint &position)
{
uint prevTotal = total;
float *tmpArray = NULL;
position++;
if (position >= total)
{
total = position;
float *tmpArray = resizeArray_by((float *)array, total);
if (tmpArray)
{
array = (float **)tmpArray;
array[position - 1] = NULL;
}
else
{
position--;
total = prevTotal;
}
}
}
void addArray_toArray_atPosition(float *add, uint size, float **& array, uint &total, uint &position)
{
uint prevPosition = position;
incrementArray_andPosition(array, total, position);
if (position != prevPosition)
{
float *tmpArray = NULL;
if (!array[position - 1] || mHasLengthChanged)
{
tmpArray = resizeArray_by(array[position - 1], size);
}
if (tmpArray)
{
memcpy(tmpArray, add, size);
array[position - 1] = tmpArray;
}
}
}
After all my fixes, the code inits probably. The interesting thing here, is after sorting out the arrays, I allocate with malloc a huge array, so to reorder the arrays into one array to be used as an GL_ARRAY_BUFFER. If realloc is no allocating because of a lack of space, then why isn't allocating?
Finally, this results it crashing in the end anyway. After going through the render function once it crashes. If I removed all my fixes and just caught when realloc doesn't allocate it would work fine. Which begs the question, what is wrong with mallocing my array instead of reallocing to cause so problems further down the line?
My Array's are pointer of pointers of floats. When I grow the array it is converted into a pointer to floats and reallocated. I am building on Android, so this is why I assumed there to be a lack of memory.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
从所有不同的信息来看(realloc 找不到内存,memcpy 表现异常,崩溃),这听起来很像堆损坏。如果没有一些代码示例来说明您正在做什么,很难确定,但似乎您在某些时候错误地管理了内存,导致堆进入无效状态。
您是否能够在 Linux 等替代平台上编译代码(您可能需要存根一些 Android 特定的 API)?如果是这样,您可以查看该平台上发生的情况和/或使用 valgrind 来帮助追捕它。
最后,既然你有这个标记的 C++,为什么你要使用 malloc/realloc 而不是
vector
(或另一个标准容器)或new
?Judging from all the different bits of information (
realloc
not finding memory,memcpy
behaving unexpectedly, crashes) this sounds much like a heap corruption. Without some code samples of exactly what you're doing it's hard to say for sure but it appears that you're mis-managing the memory at some point, causing the heap to get into an invalid state.Are you able to compile your code on an alternate platform such as Linux (you might have to stub some android specific APIs)? If so, you could see what happens on that platform and/or use valgrind to help hunt it down.
Finally, as you have this tagged C++ why are you using malloc/realloc instead of, for example,
vector
(or another standard container) ornew
?您混淆了
size
和指针类型。在内存分配中,size
是字节数,您将指针类型转换为float *
,本质上创建了一个float
数组大小size / sizeof(float)
。在 memcpy 等效代码中,您将数组视为float **
并复制它们的size
。假设 sizeof(float *) > ,这将破坏堆。 1,并且很可能是后来问题的根源。此外,如果您要将 100 大小的数组复制到 200 大小的数组,则需要复制 100 个以上的元素,而不是 200 个。复制超出数组末尾(这就是您正在做的事情)可能会导致导致程序崩溃。
动态分配的指向
float
的指针数组的类型为float **
,而不是float *
,当然也不是两者的混合。数组的大小是 malloc 和它的友元的字节数,以及所有数组操作中的元素数。memcpy
将忠实地复制字节,假设源块和目标块不重叠(并且单独分配的内存块不重叠)。但是,您已指定size - 1
作为复制的字节数,而复制的字节数应与旧数组的字节大小完全相同。 (无论如何,你在哪里得到错误的指针值?如果它在数组的扩展部分,那么你无论如何都会在那里复制垃圾。)如果memcpy给你胡言乱语,那么它一开始就变得胡言乱语,这不是你的问题。You are confusing
size
and pointer types. In the memory allocation,size
is the number of bytes, and you are converting the pointer type tofloat *
, essentially creating an array offloat
of sizesize / sizeof(float)
. In the memcpy-equivalent code, you are treating the array asfloat **
and copyingsize
of them. This will trash the heap, assuming thatsizeof(float *) > 1
, and is likely the source of later problems.Moreover, if you are copying, say, a 100-size array to a 200-size array, you need to copy over 100 elements, not 200. Copying beyond the end of an array (which is what you're doing) can lead to program crashes.
A dynamically allocated array of pointers to
float
s will be of typefloat **
, notfloat *
, and certainly not a mixture of the two. The size of the array is the number of bytes to malloc and friends, and the number of elements in all array operations.memcpy
will faithfully copy bytes, assuming the source and destination blocks don't overlap (and separately allocated memory blocks don't). However, you've specifiedsize - 1
for the number of bytes copied, when the number copied should be the exact byte size of the old array. (Where are you getting bad pointer values anyway? If it's in the expanded part of the array, you're copying garbage in there anyway.) Ifmemcpy
is giving you nonsense, it's getting nonsense to begin with, and it isn't your problem.顺便说一句,您不需要测试
array
是否为NULL
您可以
用
realloc
替换,就像malloc
一样当给定一个NULL
指针时。另一件事,要小心 size 不为 0,因为 realloc 为 0,因为 size 与
免费
。第三点,如果不是绝对必要的话,不要不要类型转换指针。您对分配函数的返回值进行了类型转换,自 ANSI-C 以来这被认为是不好的做法。它在 C++ 中是强制性的,但当您使用 C 分配时,您显然不在 C++ 中(在这种情况下,您应该使用
new
/delete
)。将数组变量强制转换为 (void *) 也是不必要的,因为如果您的参数被错误声明,它可能会隐藏一些警告(它可能是一个 int 或指向指针的指针,通过强制转换您将抑制警告)。
And btw, you don't need to test if
array
isNULL
You can replace
by
realloc
acts likemalloc
when given aNULL
pointer.Another thing, be careful that size is not 0, as realloc with 0 as size is the same as
free
.Third point, do not typecast pointers when not strictly necessary. You typecasted the return of the allocation functions, it's considered bad practice since ANSI-C. It's mandatory in C++, but as you're using the C allocation you're obviously not in C++ (in that case you should use
new
/delete
).Casting the array variable to (void *) is also unecessary as it could hide some warnings if your parameter was falsely declared (it could be an int or a pointer to pointer and by casting you would have suppressed the warning).