I do not quite understand the difference between passing to a function *mode1
or **mode2
.
I wrote some examples. (note: type
can be any type)
[Code 1]
#include <stdio.h>
void function (type *vet)
{
/* other */
}
int main ()
{
type *vet;
function (vet)
/* other */
return 0;
}
[Code 2]
#include <stdio.h>
void function (type **vet)
{
/* other */
}
int main ()
{
type *vet;
function (&vet)
/* other */
return 0;
}
I know: in the first case is a pointer, in the second case is a pointer to a pointer. But why for example in the second case if I pass &vet
can I allocate memory in function()
and free it in main()
and in the first one not?
I search someone who explain me the differences well. What can I do in the two cases? How and where to malloc or realloc? And free? And modify vet in the function?
The main (most significant) difference is whether the value in the calling function can be changed.
*vet
in the called function, you can modify the value in the called function.Why in the second case if I pass
&vet
can I allocate memory infunction()
and free it inmain()
and in the first one not?
In the second case, the code in function()
can modify the actual pointer in main()
, so the value of vet
in main()
ends up with the allocated pointer value, which can therefore be freed. In the first case, the value in main()
is not modified by the called function, so the data can't be freed by main()
.
How and where to malloc or realloc? And free?
In the first case, you can use malloc()
or realloc()
in the function, but you should also free the allocated memory before return unless your code stores the value in a global variable (in which case you can delegate to some other code to handle the free()
, but it had better be very clear which code has the responsibility, and in any case using global variables is probably not a good idea). Or unless you change the function signature and return a pointer to the allocated data which should be freed by the calling code.
In the second case, you can allocate or reallocate memory in the called function and leave it allocated to be used by other functions and to be freed by the calling function.
And modify vet in the function?
In both functions, you can modify the local vet
variable as you see fit; this is true of any parameter to any function. What you can't necessarily do is modify values in the calling function; you have to have a pointer to value in the calling function to do that. In the first function, you can't change the value of vet
in main()
; in the second, you can. In both functions, you can change what vet
points at. (One minor problem is the conflation of the name vet
in the three contexts — the main()
and the two different functions. The name vet
in the two functions points at different types of things.)
But is it freed in
function()
like, for example, this?
#include <stdio.h>
#define NUM (10)
struct example
{
/* ... */
}
void dealloc (struct example *pointer)
{
free (pointer);
}
int main()
{
struct example *e;
e = malloc (NUM * sizeof(struct example));
if (e == NULL)
return -1;
struct example *e_copy = e;
dealloc (e_copy);
return 0;
}
This code is legitimate. You pass (a copy of) the value of the pointer to the dealloc()
function; it passes that pointer to free()
which releases the allocated memory. After dealloc()
returns, the pointer values in e
and e_copy
are the same as before, but they no longer point to allocated memory and any use of the value leads to undefined behaviour. A new value could be assigned to them; the old value cannot be dereferenced reliably.
And what is the difference from this?
#include <stdio.h>
#define NUM (10)
struct example
{
/* ... */
}
int main()
{
struct example *e;
e = malloc (NUM * sizeof(struct example));
if (e == NULL)
return -1;
struct example *e_copy = e;
free (e_copy);
return 0;
}
The difference between this example and the last is that you call free()
directly in main()
, rather than from a function dealloc()
.
What would make a difference is:
void dealloc(struct example **eptr)
{
free(*eptr);
*eptr = 0;
}
int main()
{
...
dealloc(&e_copy);
return 0;
}
In this case, after dealloc()
returns, e_copy
is a null pointer. You could pass it to free()
again because freeing the null pointer is a no-op. Freeing a non-null pointer twice is undefined behaviour — it generally leads to problems and should be avoided at all costs. Note that even now, e
contains the pointer that was originally returned by malloc()
; but any use of that pointer value leads to undefined behaviour again (but setting e = 0;
or e = NULL;
or e = e_copy;
is fine, and using e = malloc(sizeof(struct example));
or such like also works.