malloc vs calloc

D

David Hill

Is there a difference between:

/* code 1 */
struct sample test;
test = malloc(sizeof(struct sample));
memset(&test, 0, sizeof(test));

/* code 2 */
struct sample test;
test = calloc(1, sizeof(struct sample));

Why would code 1 be chosen over code 2? I tend to see many instances of
code 1 in source code and hardly any instances of code 2.

Thanks
David
 
B

Ben Pfaff

David Hill said:
Is there a difference between:

/* code 1 */
struct sample test;
test = malloc(sizeof(struct sample));

`test' is not a pointer, so this assignment is invalid. I will
assume you meant to declare `test' as type `struct sample *'.

When calling malloc(), I recommend using the sizeof operator on
the object you are allocating, not on the type. For instance,
*don't* write this:

int *x = malloc (sizeof (int) * 128); /* Don't do this! */

Instead, write it this way:

int *x = malloc (sizeof *x * 128);

There's a few reasons to do it this way:

* If you ever change the type that `x' points to, it's not
necessary to change the malloc() call as well.

This is more of a problem in a large program, but it's still
convenient in a small one.

* Taking the size of an object makes writing the statement
less error-prone. You can verify that the sizeof syntax is
correct without having to look at the declaration.
memset(&test, 0, sizeof(test));

`&test' would be correct if `test' didn't have a pointer type,
but since you meant it to have a pointer type (or why would you
assign it the result of malloc()) this should be changed to
memset(test, 0, sizeof *test);
/* code 2 */
struct sample test;
test = calloc(1, sizeof(struct sample));

Again, `test' needs to have a pointer type for this to be
reasonable.
Why would code 1 be chosen over code 2? I tend to see many instances of
code 1 in source code and hardly any instances of code 2.

The latter is more straightforward. It might even be faster if
the implementation has a source of pre-zeroed storage.

Often neither is portably correct, because pointer and
floating-point types, among others, need not have a null pointer
or zero value when set to all-bits-zero.
 
A

Arthur J. O'Dwyer

Is there a difference between:

/* code 1 */
struct sample test;
test = malloc(sizeof(struct sample));

Whoops! Corrected the obvious typos below:

/* code 1 */
struct sample *test;
test = malloc(sizeof *test);
memset(test, 0, sizeof *test);


/* code 2 */
struct sample *test;
test = calloc(1, sizeof *test);

Why would code 1 be chosen over code 2? I tend to see many instances of
code 1 in source code and hardly any instances of code 2.

OMMV, but I personally avoid 'calloc', along with some library
functions such as 'memmove', because I think their *exact* effects
are obscure, and I don't ever feel like reading manpages when I
don't have to.

In particular for your example, 'calloc' takes two arguments whose
order matters -- so I'd have to get that right, where with 'malloc'
I don't. Ease of use.

Secondly, 'calloc' tries to set all the newly allocated bytes to zero.
That generally takes O(n) time. Now C in general has a very close
correspondence between C-language statements and machine-level
instructions, and I feel that if I'm going to be performing a very
expensive setup step like "set this whole block to zero," that's
something that should *not* be hidden away inside a library function
call. The 'malloc'/'memset' idiom makes the cost of setting '*test'
to zero slightly more noticeable.

Those are the two big reasons I don't use 'calloc', but there's
one more: it is rarely the right tool for the job.

In fact, *neither* of those fragments is going to do what you want,
in the general case: setting a struct's bytes to all zero isn't the
same as setting each member of that struct to zero, especially when
it comes to pointers and floating-point numbers. There's no easy
way to set each member of a dynamically allocated 'struct' to zero,
though -- you have to do it one-by-one.

HTH,
-Arthur
 
A

Artie Gold

David said:
Is there a difference between:

/* code 1 */
struct sample test;
test = malloc(sizeof(struct sample));
memset(&test, 0, sizeof(test));

Well, the above is just plain wrong! ITYM:

struct sample * test;
test = malloc(sizeof *test);
if (test == NULL) {
/* take appropriate action */
}
memset(test, 0, sizeof *test);
/* code 2 */
struct sample test;
test = calloc(1, sizeof(struct sample));

Same problem. ITYM:

struct sample * test;
test = calloc(1, sizeof *test);
/* appropriate test for calloc failure */

Why would code 1 be chosen over code 2? I tend to see many instances of
code 1 in source code and hardly any instances of code 2.

Considering the fact that it's wrong [;-)], I doubt it.

Once corrected, however, they are equivalent.

HTH,
--ag
 
J

Jack Klein

Whoops! Corrected the obvious typos below:

/* code 1 */
struct sample *test;
test = malloc(sizeof *test);
memset(test, 0, sizeof *test);


/* code 2 */
struct sample *test;
test = calloc(1, sizeof *test);



OMMV, but I personally avoid 'calloc', along with some library
functions such as 'memmove', because I think their *exact* effects
are obscure, and I don't ever feel like reading manpages when I
don't have to.

You think right about calloc(), wrong about memmove(). The effects of
the latter are perfectly defined.
In particular for your example, 'calloc' takes two arguments whose
order matters -- so I'd have to get that right, where with 'malloc'
I don't. Ease of use.

The order of the arguments to calloc() does NOT matter. Nor do the
exact values. ONLY the product of the two values matters.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++ ftp://snurse-l.org/pub/acllc-c++/faq
 
A

Al Bowers

Arthur said:
Whoops! Corrected the obvious typos below:

/* code 1 */
struct sample *test;
test = malloc(sizeof *test);
memset(test, 0, sizeof *test);


/* code 2 */
struct sample *test;
test = calloc(1, sizeof *test);




.....snip........


In fact, *neither* of those fragments is going to do what you want,
in the general case: setting a struct's bytes to all zero isn't the
same as setting each member of that struct to zero, especially when
it comes to pointers and floating-point numbers. There's no easy
way to set each member of a dynamically allocated 'struct' to zero,
though -- you have to do it one-by-one.

You can assign a struct object the value of a static struct object.
I'm not sure if this is included in your reference of one-by-one.

#include <stdio.h>

struct test
{
int i;
double d;
int *ip;
} init;

int main(void)
{
struct test a = init;

printf("a.i = %d\na.d = %f\na.ip is%s a null pointer\n",
a.i,a.d,(a.ip==NULL)?"":" not");
return 0;
}
 
R

Robert Stankowic

David Hill said:
Is there a difference between:

/* code 1 */
struct sample test;
test = malloc(sizeof(struct sample));
memset(&test, 0, sizeof(test));

/* code 2 */
struct sample test;
test = calloc(1, sizeof(struct sample));

Why would code 1 be chosen over code 2? I tend to see many instances of
code 1 in source code and hardly any instances of code 2.

I think, zeroing a struct with either calloc() or malloc()/memset() is a Bad
Idea :). If you need just one struct, use

struct sample test = {0};

Which is guaranteed to fill all the members with the appropriate zero values
(NULL for pointers, 0.0 for floating point values etc).
And if you have to malloc() an array of structs and zero them it's better to
write something like
(snippet only, headers, #defines etc omitted)

size_t i;
struct sample empty = {0};
struct sample *test = malloc(NUMBER_OF_STRUCTS_WANTED * sizeof *test);
if(test)
{
for(i = 0; i < NUMBER_OF_STRUCTS_WANTED; i++)
{
test = empty;
}
/*do something with test*/
free(test);
}

Using an initializer gives you also the possibility to initialize your
structs to non-zero values:

struct tag_test
{
size_t size;
int available;
char some_text[SOME_SIZE];
}init_struct = {sizeof init_struct, 1, "Item"};


Robert
 
D

Dan Pop

In particular for your example, 'calloc' takes two arguments whose
order matters -- so I'd have to get that right, where with 'malloc'
I don't.

Please elaborate. What happens if you get the calloc argument order
"wrong"?
Secondly, 'calloc' tries to set all the newly allocated bytes to zero.
That generally takes O(n) time. Now C in general has a very close
correspondence between C-language statements and machine-level
instructions, and I feel that if I'm going to be performing a very
expensive setup step like "set this whole block to zero," that's
something that should *not* be hidden away inside a library function
call. The 'malloc'/'memset' idiom makes the cost of setting '*test'
to zero slightly more noticeable.

Isn't it still hidden away inside a library function call?
Those are the two big reasons I don't use 'calloc', but there's
one more: it is rarely the right tool for the job.

It's not that exotic to initialise an object to all zeroes at the very
point you bring it into existence. calloc can achieve this for quite a
wide range of objects (only floating point and pointers can't be
*portably* set to zero this way, but, if your code is already
non-portable, this is the least of your worries: conforming
implementations where all bits zero don't work as expected for floating
point and pointers are few and far between).

Dan
 
A

Al Bowers

Dan said:
Please elaborate. What happens if you get the calloc argument order
"wrong"?

The Standard defines what occurs if the argument order is not "wrong".
What does the Standard state should you reverse this order?
 
M

Mark Gordon

The Standard defines what occurs if the argument order is not "wrong".
What does the Standard state should you reverse this order?

Instead of enough space for 100 elements 10 bytes long you will get
enough space for 10 elements 100 bytes long, for example. Fortunately
(or deliberately) both parameters to calloc are of type size_t, so
swapping them won't cause overflow problems, and last I checked x*y==y*x
 
D

Dan Pop

The Standard defines what occurs if the argument order is not "wrong".
What does the Standard state should you reverse this order?

The obvious: that, instead of allocating space for N objects of M bytes
each, you allocate memory for M objects of N bytes each. That is
assuming that the "right" calloc call was calloc(N, M).

Now, pray tell, what is the difference between the two scenarios,
considering the general properties of malloc and friends?

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?

Trivia quizz, for the beginner: there is a similar issue with the second
and third arguments of a fread or fwrite call, but there it does make a
real difference. Explain the difference between fread(buf, 1, 10, fp)
and fread(buf, 10, 1, fp).

Dan
 
A

Al Bowers

Dan said:
The obvious: that, instead of allocating space for N objects of M bytes
each, you allocate memory for M objects of N bytes each. That is
assuming that the "right" calloc call was calloc(N, M).

The Standard states that? Chapter and verse please!

Or is this your obvious conclusion?
 
S

Simon Biber

Dan Pop said:
Trivia quizz, for the beginner: there is a similar issue with the second
and third arguments of a fread or fwrite call, but there it does make a
real difference. Explain the difference between fread(buf, 1, 10, fp)
and fread(buf, 10, 1, fp).

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.
 
A

Arthur J. O'Dwyer

Dan said:
Al Bowers said:
Dan Pop wrote: [re my first reason why I avoid calloc]
Please elaborate. What happens if you get the calloc argument order
"wrong"?

The Standard defines what occurs if the argument order is not "wrong".
What does the Standard state should you reverse this order?

The obvious: that, instead of allocating space for N objects of M bytes
each, you allocate memory for M objects of N bytes each. That is
assuming that the "right" calloc call was calloc(N, M).

The Standard states that? Chapter and verse please!

Or is this your obvious conclusion?

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. However, I see that some people *aren't* positively
of that opinion, and will demand proof of correctness.
Quod erat demonstrandum: it's easier to use malloc and avoid
the pedantic arguments, than use calloc and risk having to debate
obscure little points of the Standard. :)

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.]]

-Arthur
 
J

Joona I Palaste

Arthur J. O'Dwyer said:
Dan said:
Dan Pop wrote: [re my first reason why I avoid calloc]
Please elaborate. What happens if you get the calloc argument order
"wrong"?

The Standard defines what occurs if the argument order is not "wrong".
What does the Standard state should you reverse this order?

The obvious: that, instead of allocating space for N objects of M bytes
each, you allocate memory for M objects of N bytes each. That is
assuming that the "right" calloc call was calloc(N, M).

The Standard states that? Chapter and verse please!

Or is this your obvious conclusion?
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. However, I see that some people *aren't* positively
of that opinion, and will demand proof of correctness.
Quod erat demonstrandum: it's easier to use malloc and avoid
the pedantic arguments, than use calloc and risk having to debate
obscure little points of the Standard. :)

I am of the opinion that Dan Pop is completely correct. The effects of
reversing the order of calloc()'s parameters is nothing. Zippo. Nada.
Zilch. The fat lady has sung.
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? Was there really a time when
it mattered, or was it just aesthetics? A remnant of B, BCPL, or an
even earlier language?
And as I've myself asked before, what's the point in gets() existing
in the first place?
 
P

pete

Al said:
The Standard states that? Chapter and verse please!

My understanding of this part of the standard,
agrees with Dan Pop.

N869
7.20.3.1 The calloc function
Synopsis
[#1]
#include <stdlib.h>
void *calloc(size_t nmemb, size_t size);
Description
[#2] The calloc function allocates space for an array of
nmemb objects, each of whose size is size.
 
A

Alan Balmer

OTOH, Dan, if the argument order really *doesn't* matter, then
why does the Standard bother to specify which parameter is
which?

That's easy: because it's simpler than explaining that it doesn't
matter.
 
A

Alan Balmer

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? Was there really a time when
it mattered, or was it just aesthetics? A remnant of B, BCPL, or an
even earlier language?

I dunno about history, but it's a documentation aid - emphasizing that
you're asking for N spaces for an object of some certain size. Also
useful, since when calculating space requirements,most likely what you
want is N objects of type struct foo.

Now, the question is why doesn't malloc take two parameters?
 

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

Staff online

Members online

Forum statistics

Threads
473,992
Messages
2,570,220
Members
46,805
Latest member
ClydeHeld1

Latest Threads

Top