4

I am trying to dynamically reallocate memory for an array of structs (actually an array each of 2 structs but 1 included here for simplicity) that is being read from/to a file or inputted by the user.

typedef Struct
{
    char surname[21];
    char firstname[21];
    char username[21];
...
} User;

...in main():

int size = 0; /* stores no. of structs */
User* user_array = (User *) calloc(1, sizeof(User));
if(user_array == NULL)
{
    printf("Cannot allocate initial memory for data\n");
    exit(1);
}
else
    size++;

I am then trying to use a function call to increase the array when needed:

int growArray(User user_array*, int size)
{
    User *temp;
    size++;
    temp = (User *) realloc(user_array, (size * sizeof(User));
    if(temp == NULL)
    {
        printf("Cannot allocate more memory.\n");
        exit(1);
    }
    else
        user_array = temp;
    return size;
}

Unfortunately the realloc never works. Both structs are only about 200 bytes per instance and setting the initial size to say 10 will work fine, so there must be something wrong with the way I am trying to use realloc.

System is Win 7 64, on Core i5 with 4GB, running Quincy (a MinGW GUI).

thelionroars1337
  • 188
  • 1
  • 3
  • 10

2 Answers2

8

realloc changes the size of the memory pointed to by user_array to the specified size, it doesn't increase it by size. Seeing as your function is called growArray, i'd presume you want it to increase the size of the array by size, in which case you need to:

int growArray(User **user_array, int currentSize, int numNewElems)
{
    const int totalSize = currentSize + numNewElems;
    User *temp = (User*)realloc(*user_array, (totalSize * sizeof(User)));

    if (temp == NULL)
    {
        printf("Cannot allocate more memory.\n");
        return 0;
    }
    else
    {
        *user_array = temp;
    }

    return totalSize;
}

Note that growArray takes the address of user_array, the reason for this is that realloc might move the memory if it couldn't extend the existing block to the required size.

To use it:

int size = 0;
User* user_array = (User *) calloc(1, sizeof(User));
if(user_array == NULL)
{
    printf("Cannot allocate initial memory for data\n");
    exit(1);
}

/* add 10 new elements to the array */
size = growArray(&user_array, size, 10);
Node
  • 3,443
  • 16
  • 18
  • Size is equal to the number of structs in the array (before it is increased) when it is passed to growArray. The size++ in growArray will increase this to the new number (intended to be increased by 1 at a time - from an unknown no. of entries in the file or by user adding) so I believe size * sizeof(User) is correct for this approach. I notice you have used double indirection operator as @cnicutar has, I'm still trying to get my head around what is happening there. This must be where I am going wrong... if I don't do it this way, I will still be using the old start address of user_array? – thelionroars1337 May 29 '11 at 22:54
  • 1
    Yeah, that could be your problem. `realloc` might not be able to extend your existing `user_array` pointers memory block to be big enough for the new size. If this happens, it allocates a **new** block of memory somewhere else, and copies everything from the `user_array` over. The return value is the new memory location. Using the pointer-to-a-pointer allows `growArray` to update the value of `user_array` of the caller, as its previous value is now invalid. – Node May 29 '11 at 23:03
4

You're changing the value of user_array locally. The value is lost when the function returns. Pass a pointer to the user_array pointer instead.

Richard Pennington
  • 19,673
  • 4
  • 43
  • 72