Search code examples
cstructmallocrealloc

Why does my C program crash when I try to realloc() a pointer array of structs?


In the code below, I'm trying to expand an array of key value structs using realloc().

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

typedef struct {
    char key[25];
    char value[25];
} keyValPair;

void inputKeyVal(keyValPair* arr, int n) {
    char inputKey[25];
    char inputVal[25];
    printf("input key: ");
    scanf(" %24s", &inputKey);
    printf("input value: ");
    scanf(" %24s", &inputVal);
    n++;
    arr = (keyValPair*) realloc( (keyValPair*) arr, n*sizeof(keyValPair));
    strcpy(arr[n-1].key, inputKey);
    strcpy(arr[n-1].value, inputVal);
}

int main() {
    keyValPair initArr[] = {{"foo", "bar"}, {"a", "b"}};
    int n = sizeof(initArr)/sizeof(keyValPair);
    keyValPair* arr = malloc(n * sizeof(keyValPair));
    arr = initArr;
    inputKeyVal(arr, n);
}

Whenever I run it however, it runs up to the input prompt, before crashing at the realloc() attempt. I still can't figure out why or how to fix it. Fairly new to C, so a detailed explanation would be much appreciated and would go a long way.


Solution

  • I think that there are three problems.

    arr = initArr; overwrites the address of arr by initArr, so that realloc can't take the address which has been allocated by malloc. To keep the address allocated by malloc, the contents of initArr should be copied into arr.

    #include <stddef.h>
    
    for (size_t i = 0; i < sizeof(initArr) / sizeof(initArr[0]); i++) {
       arr[i] = initArr[i];
    }
    

    The last argument for scanf is wrong. & is unnecessary.

    scanf("%24s", inputKey);
    

    After inputKeyVal, arr at main loses valid address because it is reallocated in inputKeyVal. If you require the correct address which has been reallocated by realloc, inputKeyVal should return the reallocated address.

    keyValPair* inputKeyVal(keyValPair* arr, int n) {
      /* snipped */
      return arr;
    }
    
    int main() {
      /* snipped */
      arr = inputKeyVal(arr, n);
      /* do something for arr */
      free(arr);
      return 0;
    }