0

An array of pointers of chars is not getting changed in main. Here's the situation: Inside main, an array of pointers of chars is declared and memory is allocated for it. main calls another function called AddItems which adds items to the list and that function calls doubleSize to double the size of the list. Everything is working as expected in terms of adding new items inside AddItems and doubling the size of the array. However, the problem is that when AddItems returns, main still has an older copy of the list, even though we're passing a pointer to the list.

Here's a MWE:

#define INITIAL_SIZE (4)
int main(void)
{
    char **list = (char **) malloc(INITIAL_SIZE * sizeof(char *));
    int list_size = INITIAL_SIZE;

    for (int i = 0; i < list_size; i++) {
        list[i] = (char *) malloc(5 * sizeof(char));
        strcpy(list[i], "jane");
    }
    printf("main--> address of list: %p\n", list); 
    /* output = 0x7fc15e402b90 */
    addItems(list, &list_size);
    /* After adding items: */
    printf("main--> address of list: %p\n", list); 
    /* output = 0x7fc15e402b90 (no change) */

    return 0;
}

Here are the other two example functions:

void doubleSize(char ***list, int *current_size)
{
    char **newList = (char**) malloc(*current_size * 2 * sizeof(char*));
    for (int i = 0; i < *current_size; i++)
        newList[i] = (*list)[i];
    free(*list);
    *list = newList;
    *current_size = (*current_size) * 2;
}
void addItems(char **list, int * size)
{
    printf("Before doubling: %p\n", list);
    /* Output: 0x7fc15e402b90 */
    /* Double the size */
    doubleSize(&list, size);
    printf("After doubling: %p\n", list);
    /* Output: 0x7fc15e402be0 */
}

The address of list is getting changed to the newly created array inside doubleSize and also inside addItems but not inside the main function, even though we're passing a pointer to the array. What am I missing here?

NightOwl
  • 3
  • 1
  • 1
    `addItems(list, ...` --> You need to pass the address of `list` to affect `list` inside `main`, or you can return the `realloc`ated pointer. – David Ranieri Oct 25 '20 at 07:38
  • @DavidRanieri Oh but what about array decay? Doesn't the array decay to a pointer naturally? When we passing `list` to `addItems` we're passing a pointer of `list`, right? – NightOwl Oct 25 '20 at 07:40
  • Re "*Oh but what about array decay?*", You have no arrays. – ikegami Oct 25 '20 at 07:47
  • @NightOwl this short snippet https://ideone.com/BAZGeU illustrates your problem. – David Ranieri Oct 25 '20 at 07:52

2 Answers2

1

you could also try as below by modifying addItems

char** addItems(char **list, int * size)
{
    printf("Before doubling: %p\n", list);
    /* Output: 0x7fc15e402b90 */
    /* Double the size */
    doubleSize(&list, size);
    printf("After doubling: %p\n", list);
    /* Output: 0x7fc15e402be0 */
    return list;
}

And the call from main should be:

list = addItems(list, &list_size);
csavvy
  • 761
  • 4
  • 13
0

If you want a function to change something, you need to pass its address (or use a global).

You didn't, so it couldn't. Simple as that.


At no point after the first line of main do you modify main's list. Remember that C only passes the value of variables to functions (pass by copy), and that the value of the variable is the address of the allocated block.

If you want addList to be able to change main's list, you will need to pass the address of the variable list itself (&list).

You're apparently aware of the concept since you did exactly that in addList. You wanted doubleSize to change addList's list, so you passed its address to doubleSize.


Tip: It would be best to use realloc in doubleSize.

void doubleSize(char ***list, size_t *size) {
    size_t new_size = *size * 2;
    char **new_list = realloc(*list, new_size);
    if (!new_list) [
        // Ignoring out-of-memory errors.
    }

    *list = new_list;
    *size = new_size;
}

Since we're ignoring out-of-memory errors, the above simplifies to

void doubleSize(char ***list, size_t *size) {
    *list = realloc(*list, ( *size *= 2 ));
}
ikegami
  • 367,544
  • 15
  • 269
  • 518