Memory corruption in dynamic array of strings

I put together a C function to add strings to a dynamic array of strings (mostly for educational purpose to explain pointers to my kid). It works, but sometimes one or two strings in the array becomes corrupted. Running example on 64 bit Ubuntu, gcc ver. 4.8.4

Hope my code is self-explanatory:

#include <stdio.h>

main(int argc, char *argv[])
{
  char  **list = NULL;
  long  lcnt = 0;
  int   n;

        add_str2list(&list, "1.ABCDEF", &lcnt);
        add_str2list(&list, "2.123456", &lcnt);
        add_str2list(&list, "3.qwerty", &lcnt);
        add_str2list(&list, "4.654321", &lcnt);
        add_str2list(&list, "5.zxc", &lcnt);
        add_str2list(&list, "6.asd", &lcnt);

        printf("list is at %p\n", &list);
        for(n = 0; n < lcnt; n++)
        {
                printf("%i) %p <%s>\n", n, &list[n], list[n]);
        }
        return(0);
}

And here is the culprit, I removed error checking and temp pointer to hold results of the realloc for brevity:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

add_str2list(char ***arr, const char *str, long *cnt)
{
  const int     newsz   = sizeof(char *) * (*cnt + 1);
  const long    indx    = *cnt;

        if(*cnt == 0)
                *arr = malloc(newsz);
        else
                **arr = realloc(**arr, newsz);

        arr[0][indx] = strdup(str);
        *cnt = *cnt + 1;
        return(0);
}

Result:

list is at 0x7ffce9962180
0) 0x124c010 <1.ABCDEF>
1) 0x124c018 <2.123456>
2) 0x124c020 <3.qwerty>
3) 0x124c028 <$>
4) 0x124c030 <5.zxc>
5) 0x124c038 <6.asd>

The length of those strings does not seem to matter. If I have 2 - 3 strings in the array it is OK, but when I add more than 4 then some strings got corrupted.

When I debug I see it happens when indx is 4 and I assign address of duplicated string to the array: arr[0][indx] = strdup(str);

Any help with finding the bug would be appreciated.

Also, I hate the [0][indx] notation, but could not come up with a better one.

       if(*cnt == 0)
                *arr = malloc(newsz);
        else
                **arr = realloc(**arr, newsz);

**arr accesses the first element, not the base. Remove one * from these dereferences.

2 Likes

(*arr)[0], (*arr)[1], etc.