This has been something that has bothered me for ages now.
We are all taught in school (at least, I was) that you MUST free every pointer that is allocated. I\'m a
=== What about future proofing and code reuse? ===
If you don't write the code to free the objects, then you are limiting the code to only being safe to use when you can depend on the memory being free'd by the process being closed ... i.e. small one-time use projects or "throw-away"[1] projects)... where you know when the process will end.
If you do write the code that free()s all your dynamically allocated memory, then you are future proofing the code and letting others use it in a larger project.
[1] regarding "throw-away" projects. Code used in "Throw-away" projects has a way of not being thrown away. Next thing you know ten years have passed and your "throw-away" code is still being used).
I heard a story about some guy who wrote some code just for fun to make his hardware work better. He said "just a hobby, won't be big and professional". Years later lots of people are using his "hobby" code.
You are absolutely correct in that respect. In small trivial programs where a variable must exist until the death of the program, there is no real benefit to deallocating the memory.
In fact, I had once been involved in a project where each execution of the program was very complex but relatively short-lived, and the decision was to just keep memory allocated and not destabilize the project by making mistakes deallocating it.
That being said, in most programs this is not really an option, or it can lead you to run out of memory.
There are various reasons for this:
All desktop and server environments simply release the entire memory space on exit(). They are unaware of program-internal data structures such as heaps.
Almost all free()
implementations do not ever return memory to the operating system anyway.
More importantly, it's a waste of time when done right before exit(). At exit, memory pages and swap space are simply released. By contrast, a series of free() calls will burn CPU time and can result in disk paging operations, cache misses, and cache evictions.
Regarding the possiblility of future code reuse justifing the certainty of pointless ops: that's a consideration but it's arguably not the Agile way. YAGNI!
I completely disagree with everyone who says OP is correct or there is no harm.
Everyone is talking about a modern and/or legacy OS's.
But what if I'm in an environment where I simply have no OS? Where there isn't anything?
Imagine now you are using thread styled interrupts and allocate memory. In the C standard ISO/IEC:9899 is the lifetime of memory stated as:
7.20.3 Memory management functions
1 The order and contiguity of storage allocated by successive calls to the calloc, malloc, and realloc functions is unspecified. The pointer returned if the allocation succeeds is suitably aligned so that it may be assigned to a pointer to any type of object and then used to access such an object or an array of such objects in the space allocated (until the space is explicitly deallocated). The lifetime of an allocated object extends from the allocation until the deallocation.[...]
So it has not to be given that the environment is doing the freeing job for you. Otherwise it would be added to the last sentence: "Or until the program terminates."
So in other words: Not freeing memory is not just bad practice. It produces non portable and not C conform code. Which can at least be seen as 'correct, if the following: [...], is supported by environment'.
But in cases where you have no OS at all, no one is doing the job for you (I know generally you don't allocate and reallocate memory on embedded systems, but there are cases where you may want to.)
So speaking in general plain C (as which the OP is tagged), this is simply producing erroneous and non portable code.
I think that your two examples are actually only one: the free()
should occur only at the end of the process, which as you point out is useless since the process is terminating.
In you second example though, the only difference is that you allow an undefined number of malloc()
, which could lead to running out of memory. The only way to handle the situation is to check the return code of malloc()
and act accordingly.
I typically free every allocated block once I'm sure that I'm done with it. Today, my program's entry point might be main(int argc, char *argv[])
, but tomorrow it might be foo_entry_point(char **args, struct foo *f)
and typed as a function pointer.
So, if that happens, I now have a leak.
Regarding your second question, if my program took input like a=5, I would allocate space for a, or re-allocate the same space on a subsequent a="foo". This would remain allocated until:
I can not think of any modern OS that does not reclaim memory after a process exits. Then again, free() is cheap, why not clean up? As others have said, tools like valgrind are great for spotting leaks that you really do need to worry about. Even though the blocks you example would be labeled as 'still reachable' , its just extra noise in the output when you're trying to ensure you have no leaks.
Another myth is "If its in main(), I don't have to free it", this is incorrect. Consider the following:
char *t;
for (i=0; i < 255; i++) {
t = strdup(foo->name);
let_strtok_eat_away_at(t);
}
If that came prior to forking / daemonizing (and in theory running forever), your program has just leaked an undetermined size of t 255 times.
A good, well written program should always clean up after itself. Free all memory, flush all files, close all descriptors, unlink all temporary files, etc. This cleanup function should be reached upon normal termination, or upon receiving various kinds of fatal signals, unless you want to leave some files laying around so you can detect a crash and resume.
Really, be kind to the poor soul who has to maintain your stuff when you move on to other things .. hand it to them 'valgrind clean' :)