Reputation: 75
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?
Upvotes: 1
Views: 170
Reputation: 33601
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.
Upvotes: 6
Reputation: 519
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.
Upvotes: 0