tags:

views:

1877

answers:

4

What is the difference between doing:

ptr = (char **) malloc (MAXELEMS * sizeof(char *));
// OR
ptr = (char **) calloc (MAXELEMS, sizeof(char*));

???

EDT: When is it a good idea to use calloc over malloc or vice versa?

+16  A: 

calloc() zero-initializes the buffer, while malloc() leaves the memory uninitialized.

EDIT:

Zeroing out the memory may take a little time, so you probably want to use malloc() if that performance is an issue. If initializing the memory is more important, use calloc(). For example, calloc() might save you a call to memset().

Fred Larson
The *alloc variants are pretty mnemonic - clear-alloc, memory-alloc, re-alloc.
Jefromi
Use malloc() if you are going to set everything that you use in the allocated space. Use calloc() if you're going to leave parts of the data uninitialized - and it would be beneficial to have the unset parts zeroed.
Jonathan Leffler
`calloc` is not necessarily more expensive, since OS can do some tricks to speed it up. I know that FreeBSD, when it gets any idle CPU time, uses that to run a simple process that just goes around and zeroes out deallocated blocks of memory, and marks blocks thus processes with a flag. So when you do `calloc`, it first tries to find one of such pre-zeroed blocks and just give it to you - and most likely it will find one.
Pavel Minaev
@Pavel - I agree. Edited my answer to be less definite on the time issue.
Fred Larson
Using calloc() is probably a safer bet in general, unless you're trying to optimize every last tiny bit out of your code (and even then, as others have pointed out, your efforts may be futile).
Andrew Song
I tend to feel that if your code becomes "safer" as a result of zero-initing allocations by default, then your code is insufficiently safe whether you use malloc or calloc. Using malloc is a good indicator that the data needs initialisation - I only use calloc in cases where those 0 bytes are actually meaningful. Also note that calloc doesn't necessarily do what you think for non-char types. Nobody really uses trap representations any more, or non-IEEE floats, but that's no excuse for thinking your code is truly portable when it isn't.
Steve Jessop
"Safer" is probably an overstatement, it's more like "more likely to crash rather than silently corrupt data" - which is still relevant to code security (as a last barrier of defense), and it definitely makes it easier to debug crashes. That said, very good point about `float` (and other types for which all-bits-0 may not mean what you think they mean).
Pavel Minaev
@Pavel: `char *foo = malloc(foolen); assert(foo ` covers the debugging aspect, or you could use an eye-catcher byte other than 0. From a last-line of security POV, maybe it would be better to link against a version of malloc which clears the bytes (or sets them to an eye-catcher pointer-sized value, which is mapped to be non-readable and non-writeable), rather than have a policy to call calloc instead?
Steve Jessop
+9  A: 

A less known difference is that in operating systems with optimistic memory allocation, like Linux, the pointer returned by malloc isn't backed by real memory until the program actually touches it.

calloc does indeed touch the memory (it writes zeroes on it) and thus you'll be sure the OS is backing the allocation with actual RAM (or swap). This is also why it is slower than malloc (not only does it have to zero it, the OS must also find a suitable memory area by possibly swapping out other processes)

See for instance this SO question for further discussion about the behavior of malloc

Isak Savo
@Isak Savo, What an Answer man, I really loved It :).
mahesh
+1  A: 

There's no difference in the size of the memory block allocated. calloc just fills the memory block with physical all-zero-bits pattern. In practice it is often assumed that the objects located in the memory block allocated with calloc have initilial value as if they were initialized with literal 0, i.e. integers should have value of 0, floating-point variables - value of 0.0, pointers - the appropriate null-pointer value, and so on.

From the pedantic point of view though, calloc (as well as memset(..., 0, ...)) is only guaranteed to properly initialize (with zeroes) objects of type unsigned char. Everything else is not guaranteed to be properly initialized and may contain so called trap representation, which causes undefined behavior. In other words, for any type other than unsigned char the aforementioned all-zero-bits patterm might represent an illegal value, trap representation.

Later, in one of the Technical Corrigenda to C99 standard, the behavior was defined for all integer types (which makes sense). I.e. formally, in the current C language you can initialize only integer types with calloc (and memset(..., 0, ...)). Using it to initialize anything else in general case leads to undefined behavior, from the point of view of C language.

In practice, calloc works, as we all know :), but whether you'd want to use it (considering the above) is up to you. I personally prefer to avoid it completely, use malloc instead and perfrom my own initialization.

AndreyT
A: 

One often-overlooked advantage of calloc is that (conformant implementations of) it will help protect you against integer overflow vulnerabilities. Compare:

size_t cnt = get_int32(file);
struct foo *bar = malloc(cnt * sizeof *bar);

vs.

size_t cnt = get_int32(file);
struct foo *bar = calloc(cnt, sizeof *bar);

The former could result in a tiny allocation and subsequent buffer overflows, if cnt is greater than SIZE_MAX/sizeof *bar. The latter will automatically fail in this case since an object that large cannot be created.

Of course you may have to be on the lookout for non-conformant implementations which simply ignore the possibility of overflow... If this is a concern on platforms you target, you'll have to do a manual test for overflow anyway.

R..