malloc vs calloc

A

Arthur J. O'Dwyer

Arthur J. O'Dwyer said:
OTOH, Dan, if the argument order really *doesn't* matter, then
why does the Standard bother to specify which parameter is
which? [And why have 'calloc' take two arguments to begin with,
if it's *only* their product which matters? [Historical reasons.
But I'm interested to see what you'll say for the first question.]]

Which historical reasons would those be?

That by the time C was being standardized, 'calloc' had already
been defined for more than 10 years as taking two arguments. (My
copy of K&R1 is back! ;-)
Incidentally, K&R1 describes 'calloc' as returning a block of
memory sized "for n objects of the specified size" and suitably
aligned "for the object in question." Thus, it's conceivable
that certain pre-standard implementations might have been
optimized to return less-strictly-aligned pointers from

calloc(1024, sizeof(char))

than from

calloc(1, sizeof(my_1024_byte_object))

--hence the pair of arguments. But I have no hard evidence
to support such a conclusion.

And as I've myself asked before, what's the point in gets()
existing in the first place?

Same reason -- it was used in a lot of existing code, and the
standards committee didn't want to break that code. Sure, it
was a dumb function to create in the *very* first place, but
it probably got entrenched before anyone noticed how awful it
really could be. And by the time it was mentioned in K&R, there
was no way anyone was going to be able to displace it.

-Arthur
 
M

Mark McIntyre

For the record, I am almost positive that Dan Pop is exactly
right; getting calloc's arguments in the wrong order has absolutely
no ill effects.

I tend to agree. However, out of interest, what if the platform wanted
a specific alignment, or if there were padding after a structure's
last member?

Is it not the case that calloc (8, 7) might create eight 7 byte
objects aligned to 8 byte boundaries, while calloc(7,8) might create
seven 8 byte objects similarly aligned. The former block would then be
larger than the latter possibly?
 
P

pete

Mark said:
I tend to agree. However, out of interest, what if the platform wanted
a specific alignment, or if there were padding after a structure's
last member?

Is it not the case that calloc (8, 7) might create eight 7 byte
objects aligned to 8 byte boundaries, while calloc(7,8) might create
seven 8 byte objects similarly aligned. The former block would then be
larger than the latter possibly?

calloc is creating memory for an array.
There's no padding between elements in an array.

7.20.3 Memory management functions
[#1] The order and contiguity of storage allocated by
successive calls to the calloc, malloc, and realloc
functions is unspecified. The pointer returned if the
allocation succeeds is suitably aligned so that it may be
assigned to a pointer to any type of object and then used to
access such an object or an array of such objects in the
space allocated (until the space is explicitly freed or
reallocated).
 
C

Chris Torek

Incidentally, K&R1 describes 'calloc' as returning a block of
memory sized "for n objects of the specified size" and suitably
aligned "for the object in question." Thus, it's conceivable
that certain pre-standard implementations might have been
optimized to return less-strictly-aligned pointers from

calloc(1024, sizeof(char))

than from

calloc(1, sizeof(my_1024_byte_object))

--hence the pair of arguments. But I have no hard evidence
to support such a conclusion.

As further evidence that this was at least in the mind of whoever
wrote calloc(), in the ancient Unix C libraries (Phototypesetter
V6, maybe earlier?) one was *supposed* to free calloc()ed memory
with the companion function cfree(). But many programs just called
free() anyway -- which worked because the actual implementation of
calloc() just called malloc() -- and I imagine the idea of a separate
allocator was abandoned.

A number of the oddities and excrescences in both C and Unix are
there simply because a bad idea got entrenched. Which, interestingly,
relates to the discussion (if one can call it that) going on
elsethread, about whether to write portable code or "just get the
job done at the moment" code and worry about portability later.
It is true that "get the job done any dirty, hacky ol' way" *can*
improve one's time-to-market, which some -- perhaps too many --
companies believe is paramount, far more important than any kind
of reliability or maintainability. They may even be right (which
would explain the sad state of so much software). Yet, paradoxically,
writing portable code in the first place can *also* improve one's
time-to-market. A great deal depends on the situation, and situations
have a way of changing unexpectedly.

(My personal preference is to write code that is "as portable as
seems possible and cost-effective" from the start, so that it has
a good chance of porting when the situation does change. I think
that the time required to learn what it takes to achieve this is
well-spent. But others -- even some I consider reasonable people
-- do disagree at times. :) )
 
D

Dan Pop

Arthur J. O'Dwyer said:
OTOH, Dan, if the argument order really *doesn't* matter, then
why does the Standard bother to specify which parameter is
which? [And why have 'calloc' take two arguments to begin with,
if it's *only* their product which matters? [Historical reasons.
But I'm interested to see what you'll say for the first question.]]

Which historical reasons would those be?

That by the time C was being standardized, 'calloc' had already
been defined for more than 10 years as taking two arguments. (My
copy of K&R1 is back! ;-)
Incidentally, K&R1 describes 'calloc' as returning a block of
memory sized "for n objects of the specified size" and suitably
aligned "for the object in question." Thus, it's conceivable
that certain pre-standard implementations might have been
optimized to return less-strictly-aligned pointers from

calloc(1024, sizeof(char))

than from

calloc(1, sizeof(my_1024_byte_object))

--hence the pair of arguments. But I have no hard evidence
to support such a conclusion.

Nevertheless, your analysis makes sense.
Same reason -- it was used in a lot of existing code, and the
standards committee didn't want to break that code. Sure, it
was a dumb function to create in the *very* first place, but
it probably got entrenched before anyone noticed how awful it
really could be. And by the time it was mentioned in K&R, there
was no way anyone was going to be able to displace it.

This still doesn't explain why C89 (or even C99) didn't deprecate it.

BTW, the C standard library doesn't contain any properly designed function
for reading a line of input from a text stream. As a result, many
programmers invent their own wheel, which is downright silly. fgets()
is safe but it is also a pain in the ass to use correctly.

Dan
 
A

Al Bowers

Dan said:
If I want to allocate space for a string of 9 characters, which is the
"right" calloc call (calloc(1, 10) or calloc(10, 1)) and why?

How can you construct a "right" way?
One visualizes the allocation as an object of 1 string of 9 characters.
Thus:
calloc(1,10);

or One visualize the allocation 1 string of 9 characters as a allocation
of an array of 10 characters. Thus:
calloc(10,1);
Either way, the allocation is the same.

Consider a more complex example; an allocation of an array of a struct
type. Using the standard as as guide, the first argument would be the
nember of structs in the array and the second argument would be the
size of the struct. If one is haphazard in the order of the arguments,
the allocation would be the same, however, I would consider it sloppy
code, which may lead to code management confusion.

This code seq faults. Why?
I see, variable b, the first argument in calloc, does not
represent the numb of structs in the array.

#include <stdlib.h>
#include <stdio.h>

#define STRUCT_NR 7

struct test
{
char name[80];
char addr[80];
} init = {{"NAME GOES HERE"},{"ADDRESS GOES HERE"}};

int main(void)
{
size_t a = STRUCT_NR, b = sizeof(struct test),i;
struct test *s;

if((s = calloc(b,a)) == NULL) return EXIT_FAILURE;
/* Ok, calloc 1st argument, b, should represent num. structs*/
for(i = 0; i < b;i++) s = init;
printf("s[0].name is %s\ns[0].addr is %s\n", s[0].name,s[0].addr);
return 0;
}
 
D

Dan Pop

How can you construct a "right" way?
One visualizes the allocation as an object of 1 string of 9 characters.
Thus:
calloc(1,10);

or One visualize the allocation 1 string of 9 characters as a allocation
of an array of 10 characters. Thus:
calloc(10,1);
Either way, the allocation is the same.

You have to ask this question to the poster who thought that there is
a right way and a wrong way of specifying calloc's arguments. I didn't
put the word right between double quotes just because I cannot control
my fingers while typing ;-)
Consider a more complex example; an allocation of an array of a struct
type. Using the standard as as guide, the first argument would be the
nember of structs in the array and the second argument would be the
size of the struct. If one is haphazard in the order of the arguments,
the allocation would be the same, however, I would consider it sloppy
code, which may lead to code management confusion.

Which has exactly nothing to do with the program's correctness, from the
standard's point of view.
This code seq faults. Why?
I see, variable b, the first argument in calloc, does not
represent the numb of structs in the array.

#include <stdlib.h>
#include <stdio.h>

#define STRUCT_NR 7

struct test
{
char name[80];
char addr[80];
} init = {{"NAME GOES HERE"},{"ADDRESS GOES HERE"}};

int main(void)
{
size_t a = STRUCT_NR, b = sizeof(struct test),i;
struct test *s;

if((s = calloc(b,a)) == NULL) return EXIT_FAILURE;
/* Ok, calloc 1st argument, b, should represent num. structs*/
for(i = 0; i < b;i++) s = init;
printf("s[0].name is %s\ns[0].addr is %s\n", s[0].name,s[0].addr);
return 0;
}


The bug is NOT in the calloc() call. I entirely agree that calling
calloc according to its description has a great impact on program's
readability/maintenability, but this is NOT a correctness issue. The
code is *always* correct if the programmer is consistent in his usage
of the two arguments of calloc(), even if his usage is not the one
described in the standard.

In your example, if you used meaningful names for a and b, like nelem and
size, the bug would have been immediately obvious, despite the unorthodox
calloc call. It is your silly naming choice that obfuscates the bug: one
shouldn't derive the meaning of a variable from its position in a calloc
call.

Dan
 
D

Dan Pop

In said:
The only difference, in my experience, is in the integer value returned
from the fread function when it succeeds -- the former would return 10,
the latter would return 1.

I suppose if a read error or EOF occurred partway through the read,
the former fread call would give you more idea of exactly how much
data actually got read rather than the latter's simple yes/no reply.

Any time I post a trivia quizz for the beginners, one of the regulars
feels compelled to spoil it...

Dan
 
R

Richard Heathfield

Dan said:
In <[email protected]> "Simon Biber"


Any time I post a trivia quizz for the beginners, one of the regulars
feels compelled to spoil it...

....and then some other regular adds to your misery by maliciously correcting
your misspelling of "quiz". Life's a bitch, isn't it? :)

Oh, I nearly forgot. All spelling flames must contain a spelling error, so
here's min.
 
A

Alex

Any time I post a trivia quizz for the beginners, one of the regulars
feels compelled to spoil it...

Maybe because they fail to see the connection between this mysterious
"quizz" thing and a "quiz" :)

Alex
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,142
Latest member
arinsharma
Top