简体   繁体   中英

How can realloc not work but malloc can?

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.

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) or new ?

You are confusing size and pointer types. In the memory allocation, size is the number of bytes, and you are converting the pointer type to float * , essentially creating an array of float of size size / sizeof(float) . In the memcpy-equivalent code, you are treating the array as float ** and copying size of them. This will trash the heap, assuming that sizeof(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 type float ** , not float * , 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 specified size - 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.) If memcpy is giving you nonsense, it's getting nonsense to begin with, and it isn't your problem.

And btw, you don't need to test if array is NULL

You can replace

if (!array)
{
    tmpArray = (float *)malloc(size);
}
else
{
    tmpArray = (float *)realloc((void *)array, size);
}

by

tmpArray = realloc(array, size*sizeof (float));

realloc acts like malloc when given a NULL 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).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM