Is calloc better than malloc? Is calloc better than malloc? c c

Is calloc better than malloc?


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;//allocationstrcpy(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;//allocationstrcat(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 by s2 (including the terminating null character) to the end of the string pointed to by s1. The initial character of s2 overwrites the null character at the end of s1. [....]

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 by size 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.


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.


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_MEMORYmemset(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.