As others pointed out, you are not allowed to do anything with a free
d pointer (else that is the dreaded undefined behavior, which you should always avoid, see this).
In practice, I recommend never coding simply
free(ptr);
but always coding
free(ptr), ptr=NULL;
(since practically speaking this helps a lot to catch some bugs, except double free
s)
If ptr
is not used after that, the compiler would optimize by skipping the assignment from NULL
In practice, the compiler knows about free
and malloc
(because the standard C libraries headers would probably declare these standard functions with appropriate function attributes -understood by both GCC & Clang/LLVM) so might be able to optimize the code (according to the standard specification of malloc
& free
....), but the implementation of malloc
and free
is often provided by your C standard library (e.g. very often GNU glibc or musl-libc on Linux) so the actual behavior is provided by your libc
(not the compiler itself). Read appropriate documentation, notably free(3) man page.
BTW, on Linux, both glibc
and musl-libc
are free software, so you might study their source code to understand their behavior. They would sometimes obtain virtual memory from the kernel using a system call like mmap(2) (and later release back the memory to the kernel using munmap(2)), but they generally try to reuse previously free
d memory for future malloc
s
In practice, free
could munmap
your memory (notably for big memory malloc
-ated zones) - and then you'll get a SIGSEGV
if you dare dereferencing (later) that free
d pointer, but often (notably for small memory zones) it would simply manage to reuse that zone later. The exact behavior is implementation specific. Usually free
does not clear or write the just freed zone.
You are even allowed to redefine (i.e. re-implement) your own malloc
and free
, perhaps by linking a special library such as libtcmalloc, provided your implementation has a behavior compatible with what the C99 or C11 standard says.
On Linux, disable memory overcommit and use valgrind. Compile with gcc -Wall -Wextra
(and probably -g
when debugging; you might consider also passing -fsanitize=address
to recent gcc
or clang
at least to hunt some naughty bugs.).
BTW, sometimes Boehm's conservative garbage collector might be useful; you'll use (in your whole program) GC_MALLOC
instead of malloc
and you won't care about free
-ing memory.