2

I am using realloc() to dynamically size some arrays. Because I was writing a lot of code like this:

void *tmp;
if( (tmp = realloc(myobject, sizeof(object) * newsize) != NULL)
         myobject = tmp

I thought I'd make my code shorter by doing something like this (silly idea):

void GetSpace(void *ptr, size_t size_of_object, int newsize){
    void *tmp = NULL;
    if ((tmp = realloc(ptr, size_of_object * newsize) == NULL)
          //print error msg and exit
    else 
         ptr = tmp;
}
int main(){
    //This is an example
    double *mydata1 = (double *)malloc (sizeof double * 5);


    //later request more space for mydata1 
    GetSpace( mydata1, sizeof(double), 50);

}

This is silly since it doesn't save that many lines or make the code more readable but I'd like to know why it doesn't work the way I expect. When I use the GetSpace() for a single object only it works fine. If I run the code without initializing any of the objects I call the function with, it runs fine but when I call GetSpace() for an object, then put data in it and then call GetSpace() for another object, I get a stack trace with a message like this

*** glibc detected *** ./a.out: realloc(): invalid old size: 0x00007fff05d96790 ***

0x00007fff05d96790 is the address of the second array/object before resizing. Why does this happen?

1 Answer 1

3

In your GetSpace function, you are allocating a new block of memory with the bigger size, and assigning the address to the local variable ptr. But when the function exits, this new address is lost. Your main program still has the old value of ptr, which is now pointing to invalid (freed) memory.

You need to return the new address to the caller. Try this instead. Note that the parameter ptr is now passed by reference, so the caller's variable is updated.

void GetSpace(void **ptr, size_t size_of_object, int newsize){
    void *tmp = NULL;
    if ((tmp = realloc(*ptr, size_of_object * newsize) == NULL)
         //print error msg and exit
    else 
         *ptr = tmp;
}

EDIT: as pointed out in the comments, this still isn't ideal, as you have to do messy casting to pass the address of your pointer as a void**. An improvement would be to return the new pointer separately, as follows:

void *GetSpace(void *ptr, size_t size_of_object, int newsize){
    void *tmp = NULL;
    if ((tmp = realloc(ptr, size_of_object * newsize) == NULL)
        //print error msg and exit
    else 
        return tmp;
}

int main(){

    ...

    //later request more space for mydata1 
    mydata1 = GetSpace( mydata1, sizeof(double), 50);
}
Sign up to request clarification or add additional context in comments.

1 Comment

The problem with this approach is that now you can't pass &mydata when calling this function - the types do not match, double ** is not compatible with void **. One is forced to either use an extra intermediate void * pointer, or to use a cast (void **) &mydata (which is a hack). A better solution would be to use the return value of GetSpace to return the new pointer, instead of using a void ** parameter.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.