SM Ryan said:
Roughly speaking, you have to match frees to mallocs (or callocs).
(More precisely, if you realloc a null, you have match the free
to the realloc, but if realloc modifies a pointer from a malloc,
then you match the original *alloc.) You only free *alloc pointers
and you only free them once. On program exit some systems free
unmatched *allocs, some systems don't.
[...]
I think your statement about realloc() is a bit imprecise.
If you call realloc() with a null pointer as its first argument, it's
equivalent to calling malloc(), and you have to free the pointer that
was returned by realloc() (assuming it was non-null; if it was null,
you can free it or not, since free(NULL) does nothing).
If you call realloc() with a non-null pointer as its first argument,
the realloc() call can succeed or fail. If it succeeds, the pointer
you passed to it becomes invalid, and you need to free the pointer
returned by realloc(). If realloc() fails, the pointer you passed to
it is unchanged, and you need to free that pointer.
This implies that
ptr = ralloc(ptr, new_size);
is a bad idea, since it creates a memory leak if the realloc call
fails. (If your response to a realloc failure is going to be to abort
the program, it probably doesn't matter, but it's still a bad habit.)