Let's say I have the following code:
int *ptr = (int*) malloc(0), *ptr2;
ptr2 = (int*) malloc(4 * sizeof(int));
*(ptr2 + 1) = 3;
ptr = ptr2;
free(ptr)
Does calling free(ptr) work on the new memory block ptr is pointing to or on the null pointer?
Let's say I have the following code:
int *ptr = (int*) malloc(0), *ptr2;
ptr2 = (int*) malloc(4 * sizeof(int));
*(ptr2 + 1) = 3;
ptr = ptr2;
free(ptr)
Does calling free(ptr) work on the new memory block ptr is pointing to or on the null pointer?
Yes, in your example ptr
is set to ptr2
which comes from malloc
.
So, free(ptr);
is valid (e.g. just as if we did free(ptr2);
).
But, now, we've lost the original value of ptr
so the block from the first malloc
is now a memory leak. That is, no variable has the original value so it can't ever be freed.
To fix that, but retain your original code, we can do:
int *ptr = (int *) malloc(0), *ptr2;
ptr2 = (int *) malloc(4 * sizeof(int));
*(ptr2 + 1) = 3;
// to prevent a leak of the first malloc ...
int *ptr3 = ptr;
// without ptr3, this would "leak" the original value of ptr
ptr = ptr2;
free(ptr)
// free the first block ...
free(ptr3);
Side note: malloc
returns void *
, which works for any pointer type, so no need to cast the return value. See: Do I cast the result of malloc?
So, in the code do (e.g.):
ptr2 = malloc(4 * sizeof(int));
There is still some extra replication of code. The sizeof(int)
would have to be changed if we ever changed the type of ptr2
.
So, to "future proof" the code, many people prefer:
ptr2 = malloc(sizeof(*ptr2) * 4);
UPDATE:
You might also add a note about
malloc(0)
having implementation defined behavior. – chqrlie
Yes, malloc(0)
has implementation defined behavior. Some possibilities:
NULL
. IMO, the best optionmalloc(1)
I'd avoid the use of malloc(0)
for those reasons. It's "fragile" and of marginal utility.
I've [mostly] seen it used by novice programmers that plan to use realloc
in a loop and believe that they can't call realloc
on a NULL
pointer.
However, realloc
will accept a NULL
pointer just fine.
For example, if we were going to read a file filled with integers into an array and we didn't know how many numbers we had in the file, we might do:
#include <stdio.h>
#include <stdlib.h>
int
main(int argc,char **argv)
{
if (argc < 2)
exit(3);
// NOTE: novices do this ...
#if 0
int *ptr = malloc(0);
// NOTE: experienced programmers do this ...
#else
int *ptr = NULL;
#endif
// number of elements in the array
size_t count = 0;
// open the input file
FILE *input = fopen(argv[1],"r");
if (input == NULL) {
perror(argv[1]);
exit(4);
}
while (1) {
// increase array size
ptr = realloc(ptr,sizeof(*ptr) * (count + 1));
// out of memory ...
if (ptr == NULL) {
perror("realloc");
exit(5);
}
// decode one number from file
if (fscanf(input,"%d",&ptr[count]) != 1)
break;
// advance the count
++count;
}
// close the input stream
fclose(input);
// trim array to actual size used
ptr = realloc(ptr,sizeof(*ptr) * count);
// print the array
for (size_t idx = 0; idx < count; ++idx)
printf("%zu: %d\n",idx,ptr[idx]);
// free the array
free(ptr);
return 0;
}
Note: There are some rare occasions with special circumstances where doing malloc(0)
does make sense. Usually, where the pointer has to be passed to some code that will discern a NULL
vs. malloc(0)
vs. regular allocation. But, they are an advanced usage and I wouldn't recommend them for a beginner.
free(ptr) will release the four "ints" ptr2 points to. Changing memory that is unallocated doesn't make it allocated.
I will warn you that there is a memory leak here. The memory originally pointed to by ptr will still be allocated but unreferenced.