1

First of all I want to apologize if this is a repeated question. But I could not find any answer explaining how to do this correctly with a variable sized array.

Going straight to the code, I've got this:

void f(int[][2]);

int main(void)
{
  int (*obsF)[2] = malloc(sizeof(int)); //I reserve some memory so I can pass 
  f(obsF);                              //the array to f, since I don't know
  free(obsF);                           //its size until later working with f. 
}

void f(int obsF[][2])
{
  obsF = realloc(obsF, sizeof(int[5][2])); //The 5 is just as an example.
  // do stuff with obsF                    //I won't know this number until
}                                          //later in f.

Testing this with valgrind threw that that free(obsF); is an invalid free().

Now, if I do the same but everything in the main function like this:

int main(void)
{
  int (*obsF)[2] = malloc(sizeof(int));
  obsF = realloc(obsF, sizeof(int[5][2]));
  free(obsF);
}

Valgrind tests passed successfully with no errors.

I would like to know why this is happening and how to realloc my 2D array inside function and be able to free it from main correctly.

Any other better approach or solution is well received, as long as I can use obsF as a 2D array inside f and modify it as I wish and then use it in main.

Thanks.-

Santiago
  • 124
  • 9
  • 5
    In C all function args are **passed by value**. So `obsF = realloc()` will not change the caller's pointer value and hence the `free` call in `main` is operating on an already freed pointer. – kaylum Dec 02 '19 at 22:18
  • 1
    Note that you can allocate a null pointer to pass to `realloc`. – LegendofPedro Dec 02 '19 at 22:19
  • @kaylum I understood that when passing arrays as parameters C treats them as pointers. So I thought I was working on the same pointer. – Santiago Dec 02 '19 at 22:20
  • Looking for a better dup but here is one for now: https://stackoverflow.com/questions/25204576/c-free-invalid-pointer-allocated-in-other-function – kaylum Dec 02 '19 at 22:20
  • @kaylum how about converting your comment to the answer – artm Dec 02 '19 at 22:21
  • @LegendofPedro could you elaborate a little more please? – Santiago Dec 02 '19 at 22:21
  • @atm Don't want to add yet another answer. There must be dups. Looking. – kaylum Dec 02 '19 at 22:21
  • 1
    It's the same *value* but not the same variable. `obsF = realloc(obsF, sizeof(int[5][2]));` overwrites the argument and then throws it away, leavign a memory leak, and you then try to `free` what was already freed (not the leak). – Weather Vane Dec 02 '19 at 22:22
  • Does this answer your question? [Changing address contained by pointer using function](https://stackoverflow.com/questions/13431108/changing-address-contained-by-pointer-using-function) – kaylum Dec 02 '19 at 22:27
  • @kaylum helps me to understand my mistake, but it doesn't answer totally my question. – Santiago Dec 02 '19 at 22:53
  • @Santiago see https://stackoverflow.com/q/12134315/5495906 – LegendofPedro Dec 02 '19 at 23:34

1 Answers1

3

C passes arguments by value, not by reference. When you pass the obsF pointer to f and reallocate it, you change the value of the obsF parameter in the f function, but the variable in the main function (which determined the parameter's initial value) still holds the old pointer, which has been invalidated by the reallocation.

To fix this, you can pass a pointer to the obsF variable to f, and dereference that pointer to access the variable:

void f(int **obsF)
{
  *obsF = realloc(*obsF, sizeof(int[5][2]));
  // do stuff with obsF
}

And then call f as:

int main(void)
{
  int *obsF = malloc(sizeof(int));
  f(&obsF);
  free(obsF);
}

This way, the value of the obsF variable inside main will be updated after the call to f and the correct pointer will be freed.

user3840170
  • 26,597
  • 4
  • 30
  • 62
  • How would be the correct way to write the prototype of f? Because I cannot get it to work. – Santiago Dec 02 '19 at 22:31
  • I changed the example to use a plain `int *` instead of `int (*)[][]`; it should compile now. – user3840170 Dec 02 '19 at 22:35
  • 1
    I did not see that. Thank you very much. I can then cast the array to a 2D array, and free the old one, because it's what my program needs to handle. You helped me to solve my problem.- – Santiago Dec 02 '19 at 22:51