Invalid null pointers can either be caused by programmer error or by runtime error. Runtime errors are something a programmer can't fix, like a malloc
failing due to low memory or the network dropping a packet or the user entering something stupid. Programmer errors are caused by a programmer using the function incorrectly.
The general rule of thumb I've seen is that runtime errors should always be checked, but programmer errors don't have to be checked every time. Let's say some idiot programmer directly called graph_get_current_column_color(0)
. It will segfault the first time it's called, but once you fix it, the fix is compiled in permanently. No need to check every single time it's run.
Sometimes, especially in third party libraries, you'll see an assert
to check for the programmer errors instead of an if
statement. That allows you to compile in the checks during development, and leave them out in production code. I've also occasionally seen gratuitous checks where the source of the potential programmer error is far removed from the symptom.
Obviously, you can always find someone more pedantic, but most C programmers I know favor less cluttered code over code that is marginally safer. And "safer" is a subjective term. A blatant segfault during development is preferable to a subtle corruption error in the field.
The usual answer for this thing is to wait until you can measure if there's a problem.
My experience has been that malloc() is rarely an issue, but perhaps I also do more CPU-intensive work than you do, so malloc() isn't in the critical path.
Definitely some people are constrained by the malloc performance. See, for example, https://github.com/blog/1422-tcmalloc-and-mysql , where github switched to using TCMalloc for MySQL and got a 30% performance improvement. There's more discussion at http://www.reddit.com/r/programming/comments/18zija/github_got_30_better_performance_using_tcmalloc/ .
TCMalloc is one of several malloc replacements. Another is jemalloc, and a third is nedmalloc.
So, if you think it's a problem (eg, because profiling shows that you're stuck in malloc/free often) then try one of those out and see if it improves things.
If it's a concern now, then perhaps you can think about how your code is structured. The biggest improvement is to realize that you don't need to think of "one structure = one malloc."
For example, I once wrote a parser for a tab-separated document. While I could have turned each row and field into its own string, it was faster to scan the document, count the number of rows and columns, and do a single malloc for the row/field pointers. Then in the second step, scan the document again, assign the correct pointers to the head of each field, and replace the tabs and newlines with a NUL to get proper NUL-terminated strings for the field.
This meant that my parser now "owned" the document string, which was acceptable. And it reduced the complexity of the code, even if the malloc performance wasn't critical.
Best Answer
The main difference is that VLAs (variable length arrays) provide no mechanism for detecting allocation failures.
If you declare
and
len
exceeds the amount of available stack space, your program's behavior is undefined. There is no language mechanism either for determining in advance whether the allocation will succeed, or for determining after the fact whether it succeeded.On the other hand, if you write:
then you can handle failures gracefully, or at least guarantee that your program won't try to continue to execute after a failure.
(Well, mostly. On Linux systems,
malloc()
can allocate a chunk of address space even if there's no corresponding storage available; later attempts to use that space can invoke the OOM Killer. But checking formalloc()
failure is still good practice.)Another issue, on many systems, is that there's more space (possibly a lot more space) available for
malloc()
than for automatic objects like VLAs.And as Philip's answer already mentioned, VLAs were added in C99 (Microsoft in particular doesn't support them).
And VLAs were made optional in C11. Probably most C11 compilers will support them, but you can't count on it.