Reputation: 33607
I have just learned about the C calloc()
function the other day. Having read its description and how it differs from malloc
(1, 2), I get the idea that, as a non-embedded programmer, I should always use calloc()
. But is that really the case?
One reservation I have is the extra delay for accessing the calloc()
-ed memory, but I also wonder if there are cases when switching from malloc()
to calloc()
will break the program in some more serious way.
P. S. The zero-initializing aspect of calloc()
is quite clear to me. What I'm interested in learning about is the other difference between calloc()
and malloc()
- lazy memory allocation provided by calloc()
. Please don't post an answer if you're going to focus purely on the memory initialization aspect.
Upvotes: 20
Views: 9285
Reputation: 6404
malloc() is far more common in C code than calloc().
A text search for "malloc" will miss the calloc() calls.
Replacement libraires will often have mymalloc(), myrealloc(), myfree() but not mycalloc().
Zero-initialisation of pointers and reals isn't actually guaranteed to have the expected effect, though on every major platform all bits zero is NULL for a pointer and 0.0 for a real.
calloc() tends to hide bugs. Debug malloc usually sets a fill pattern like DEADBEEF which evaluates to a large negative number and doesn't look like real data. So the program quickly crashes and, with a debugger, the error is flushed out.
Upvotes: 1
Reputation: 604
Use calloc
for zero-filled allocations, but only when the zero-filling is really needed.
You should always use calloc(count,size)
instead of buff=malloc(total_size); memset(buff,0,total_size)
.
The call to zero-memset
is the key. Both malloc
and calloc
are translated into OS calls which do lots of optimizations, use hardware tricks whenever possible, etc. But there is little that OS can do with memset
.
On the other hand, when do you need to zero-fill the allocated memory? The only common use is for zero-ended arbitrary length elements, such as C-strings. If that's the case, sure, go with calloc
.
But if you allocate the structures in which the elements are either fixed-length or carry the length of arbitrary-sized elements with them (such as C++ strings and vectors), zero-filling is not helpful at all, and if you try to rely on it, it can lead to tricky bugs.
Suppose you write your custom linked list, and decide to skip the zeroing of the pointer to the next node by allocating the memory for the node with calloc
. It works fine, then someone uses it with custom placement new, which doesn't zero-fill. Trouble is, sometimes it will be zero-filled, and can pass all the usual testing, go in production, and there it will crash, crash sometimes, the dreaded unrepeatable bug.
For debug purposes, zero-filling is usually not that good, either. 0 is too common, you rarely can write something like assert(size);
because it's usually a valid value, too, you handle it with if(!size)
, not with asserts. On the debugger it won't catch your eye, either, there are usually zeros everywhere in your memory. The best practice is to avoid unsigned types for the lengths (signed lengths can be useful for runtime error handling and some of the most common overflow checks, too). So, while buff=malloc(total_size); memset(buff,0,total_size)
is to be avoided, the following is OK:
const signed char UNINIT_MEM=MY_SENTINEL_VALUE;
buff=malloc(total_size);
#if DEBUG_MEMORY
memset(buff,UNINIT_MEM,total_size);
#endif
In debug mode, runtime library or even OS do this for you sometimes, for example check this excellent post on VC++-specific sentinel values.
Upvotes: 3
Reputation: 134356
This is really a situation-dependent decision. Rule of thumb is
If you're first writing into the allocated memory, malloc()
is better (less possible overhead).
Example: Consider the following scenario
char * pointer = NULL;
//allocation
strcpy(pointer, source);
here, allocation can be very well using malloc()
.
If there's a possibility of read-before-write with the allocated memory, go for calloc()
, as it initializes memory. This way you can avoid the problem with unitialized memory read-before-write scenario which invokes undefined behavior.
Example:
char * pointer = NULL;
//allocation
strcat(pointer, source);
Here, strcat()
needs the first argument to be a string already, and using malloc()
to allocate cannot guarantee that. As calloc()
zero-initializes the memory, it will serve the purpose here and thus, calloc()
is the way to go for this case.
To elaborate the second scenario, quoting from C11
, chapter §7.24.3.1 (follow my emphasis)
The
strcat()
function appends a copy of the string pointed to bys2
(including the terminating null character) to the end of the string pointed to bys1
. The initial character ofs2
overwrites the null character at the end ofs1
. [....]
So, in this case, the destination pointer should be a pointer to a string. Allocating via calloc()
guarantees that while allocating using malloc()
cannot guarantee that, as we know, from chapter §7.22.3.4
The
malloc
function allocates space for an object whose size is specified bysize
and whose value is indeterminate.
EDIT:
One possible scenario where malloc()
is advised over calloc()
, is writing test stubs used for unit / integration testing. In that case, use of calloc()
can hide potential bugs which arrive with cases similar to the later one.
Upvotes: 13
Reputation: 117926
The main difference between malloc
and calloc
is that calloc
will zero-initialize your buffer, and malloc
will leave the memory uninitialized.
This gets to the common programming idiom of "don't pay for what you don't use". In other words, why zero-initialize something (which has a cost) if you don't necessarily need to (yet)?
As a side note since you tagged C++: manual memory usage using new/delete
is frowned upon in modern C++ (except in rare cases of memory pools, etc). Use of malloc/free
is even more rare and should be used very sparingly.
Upvotes: 3
Reputation: 27577
It's all about what you want to do with the memory. malloc
returns uninitialized (and possibly not even real yet) memory. calloc
return real, zero'ed memory. If you need it zero'ed, then yes, calloc
is your best option. If you don't, why pay for zero'ing with a latency hit when you don't need it?
Upvotes: 1