Hello
I would like to understand something about the Calloc function.
"
void *calloc(size_t nmemb, size_t size);
The calloc() function allocates memory for an array of nmemb elements
of size bytes each and returns a pointer to the allocated memory. The
memory is set to zero. If nmemb or size is 0, then calloc() returns
either NULL, or a unique pointer value that can later be successfully
passed to free().
"
What I don't understand is: how is this any different from allocating
memory for an array of size elements of nmemb bytes each? Does the order
of arguments make much difference really? What difference does it make
having them in one order instead of the other?
None. Well, at any rate "very little." Library functions
like qsort() and fwrite() also take element-count and element-size
parameters, and for them the order *does* matter. So it could be
argued that it would be inconsistent to arrange the calloc()
parameters the other way around. But since [1] the request size
will be the product of the two parameters, and [2] multiplication
is commutative, and [3] the allocation must be properly aligned for
any object whatsoever, even if it wouldn't fit, it really doesn't
make any difference.
And why is it inconsistent with Malloc (only one argument)? This seems
like a paradox, because in practice Calloc will be implemented by a Malloc
followed by a Bzero.
First, a lot of the Standard library functions are older than
the original ANSI Standard itself. One of the important purposes
of that Standard was to codify existing practice, ironing out the
differences that had developed between different C implementations.
The ANSI Standard took malloc() and calloc() and realloc() as they
already existed at the time, formalized their specifications, but
did not try to invent a new library. A few changes were unavoidable
(different implementations disagreed), a few were mostly cosmetic
(changing the value from `char*' to `void*', for example), but there
was no effort to "improve" the API of existing functions. That's
why (I imagine) some I/O functions put the `FILE*' parameter first
and others put it last.
So, why did the primeval calloc() have two parameters instead
of just one? I'm only guessing, but my guess is that calloc() may
have been invented on a system where memory was scarce, and perhaps
the earliest versions *did* in fact treat the parameters differently.
Maybe calloc(128,1) said "Oh, 1-byte objects: I don't need to worry
about alignment" whereas calloc(16,8) would say "Oh, 8-byte objects:
they might be `double', so I'd better use strict alignment." Such
a stratagem (if it existed; remember, I'm just guessing) ceased to
have meaning when ANSI decreed that all dynamic allocations had to
be strictly aligned, but things might have been different in the
Bronze Age.
Also, calloc(n,s) differs from malloc(n*s) when `n' and `s' are
large enough that their product is too big for a `size_t'. Imagine
a 16-bit `size_t', and consider
size_t count = 3000;
size_t esize = 32;
void *p = calloc(count, esize);
void *q = malloc(count * esize);
The calloc() call fails and returns NULL because it cannot allocate
enough memory for 3000 32-byte objects. But the product in the second
call gets truncated, and malloc() receives a request for 30464 bytes
(3000 * 32 = 96000, 96000 % 65536 = 30464) -- which it might succeed
in finding, returning a pointer to the allocated memory. Unfortunately,
the allocation is only large enough for 952 objects, so the programmer
who thinks all is well and tries to store 3000 of them there is in
for an unpleasant surprise ...
Personally, I seldom use calloc() and rely on malloc()/realloc()
instead. When I allocate memory, it's generally because I want to
store something in it; it's not often that what I want to store is
lots and lots of zero bytes.