I saw the following code:
#include <stdlib.h>
void foo(char n)
{
int (*vals)[n] = malloc(sizeof(int[n]));
for (int i = 0; i < n; i)
(*vals)[i] = i;
free(vals);
}
int main(int argc, char **argv)
{
foo(*(argv[1]));
return 0;
}
This lines makes me very uncomfortable:
free(vals);
vals
is a pointer pointing to an array. This looks right, but I just have a difficult time internalizing it, I do not know why.
I am more used to the following style:
int *p = (int*)malloc(n * sizeof(int));
......
free(p);
In this code, p
is a pointer pointing to the start of a memory region for some integers, the malloc and free are symmetric in that they both work on a pointer type; yet the original code has malloc()
working on a pointer to an array and free()
a pointer.
Out of curiosity, I modified the original code:
free(vals); ==> free(*vals);
I was expecting this change will fail at compiler, the reason is *vals
is an array now. But gcc is fine and valgrind does not complain memory leak.
I know C has a thing called array degenerates to pointer at function call. But I just cannot internalize this stuff. Sorry writing so long to describe a problem, wish you could see my struggle. Is there a definitive doc/stackoverflow/blog to clear this up - best C99 or later?
Thanks!
CodePudding user response:
writing free(*vals);
is same as writing free(vals);
edited your code to clear that a little bit
#include <stdlib.h>
#include <stdio.h>
void foo(char n)
{
int (*vals)[n] = malloc(sizeof(int[n]));
for (int i = 0; i < n; i)
(*vals)[i] = i;
printf("*val is %p\n", *vals);
printf("val is %p\n", vals);
printf("&val is %p\n", &vals);
free(vals);
}
int main()
{
foo(10);
return 0;
}
and this is the output:
*val is 0000018190365d50
val is 0000018190365d50
&val is 0000005d9dbff7b8
note that vals
is Array pointer which means that its base type is an array of n integers where the pointer val
is created in that stack and points to the whole array, not the first element only and that array is created in the heap
, to illustrate, look at the following graph:
so for example if you write:
printf("val is %p\n", vals);
printf("val 1 is %p\n", vals 1);
the output will be :
val is 00000207ef0c5d50
val 1 is 00000207ef0c5d78
note the difference between the 2 is about 40 bytes as val
points to the whole array not only one element as in case of int *p = (int*)malloc(n * sizeof(int));
note that when I say it points to the whole array, I also mean it points to the base address of the array.
in case of *Vals
, look at the next graph:
*Vals
is just an address of the first element of the array which is by the way is same as the base address of the array.
refer to free() manual, they said:
The free() function frees the memory space pointed to by ptr, which must have been returned by a previous call to malloc(), calloc() or realloc(). Otherwise, or if free(ptr) has already been called before, undefined behavior occurs. If ptr is NULL, no operation is performed.
and what does malloc()
function return ?
it returns the base address of your reserved space in heap, so writing free(vals);
is same as writing free(vals);
CodePudding user response:
This codes uses dynamic VLA.
I think that it may be easier to understand if the code is reformulated with a typedef
.
void foo(char n)
{
typedef int T[n];
T *vals = malloc(sizeof(T));
...
free(vals);
}
Now it looks like a tivial use of a single dynamic object.
To access elements of an array first the pointer has to be dereferenced *vals
forming an array, which decays to int*
pointer suitable for []
operator.