Why cast malloc's return? 
Author Message
 Why cast malloc's return?

Well the following might sound like a newbie's question:

* Why should the return-value of malloc always be casted?

I found this recommendation in several books, sometimes in this
manner:

    int nitems;
    float *p;
    nitems = ...
    p      = (float *)malloc(sizeof(float)*nitems);

But after several years of programming my preference became:

    int nitems;
    float *p;
    nitems = ...
    p      = malloc(sizeof(p[0])*nitems);

The PRO's for the 1. version i can identify are:

1.) It's K&R-compatible (malloc returns char *)
2.) Changing P's type triggers a compiler-message

The PRO for the 2. version is:

1.) changing the declaration of p doesn't harm.

I am interested in answers/opinions since I am just preparing a
beginners C-course.

--
Dr. Gunther Hess                          | University of Rostock



Sun, 28 Mar 1999 03:00:00 GMT  
 Why cast malloc's return?



Quote:
>Well the following might sound like a newbie's question:

>* Why should the return-value of malloc always be casted?

It should never be cast when writing in C. There were historic reasons
since prior to ANSI C malloc used to return char * so a cast was necessary.
However that should ne longer be an issue.

Quote:
>I found this recommendation in several books, sometimes in this
>manner:

Many authors of C books don't know what they are talking about.

Quote:
>    int nitems;
>    float *p;
>    nitems = ...
>    p      = (float *)malloc(sizeof(float)*nitems);

>But after several years of programming my preference became:

>    int nitems;
>    float *p;
>    nitems = ...
>    p      = malloc(sizeof(p[0])*nitems);

This is much better.

Quote:
>The PRO's for the 1. version i can identify are:

>1.) It's K&R-compatible (malloc returns char *)

Some might also say it is C++ compatible but it generally a bad idea to try
to write for two different languages, and malloc isn't a C++ idiom.

Quote:
>2.) Changing P's type triggers a compiler-message

I'm not convinced that this is a pro. The type of the cast is just something
else to get wrong.

Quote:
>The PRO for the 2. version is:

>1.) changing the declaration of p doesn't harm.

Casts also errors, the classic one being failure to declare malloc
appropriately (e.g. by including stdlib.h).

There are a few examples in the FAQ where the return value of malloc()
is cast. I believe Steve Summit intends to fix them at some point.

--
-----------------------------------------


-----------------------------------------



Sun, 28 Mar 1999 03:00:00 GMT  
 Why cast malloc's return?

: Well the following might sound like a newbie's question:
:
: * Why should the return-value of malloc always be casted?

As the FAQ tells us, it should not be casted at all (see Section
"Memory Allocation").

: I found this recommendation in several books, sometimes in this
: manner:
:
:     int nitems;
:     float *p;
:     nitems = ...
:     p      = (float *)malloc(sizeof(float)*nitems);
:
: But after several years of programming my preference became:
:
:     int nitems;
:     float *p;
:     nitems = ...
:     p      = malloc(sizeof(p[0])*nitems);
:
: The PRO's for the 1. version i can identify are:
:
: 1.) It's K&R-compatible (malloc returns char *)
: 2.) Changing P's type triggers a compiler-message

The CON is, that it might keep the compiler from providing you
with diagnostics if you forgot to include <stdlib.h>.

: The PRO for the 2. version is:
:
: 1.) changing the declaration of p doesn't harm.

I think p[0] should be replaced by *p in this context. I am
not sure whether using p[0] can result in undefined behaviour.
Pointer arithmetic is only allowed in the range of existing
data blocks and you don't have any data block here. However
the main question is: Is p[0] pointer arithmetic or not. I
myself would be very interested in an answer to that.

The general idea in your approach is correct and using *p
makes it the way many, many people use.

: I am interested in answers/opinions since I am just preparing a
: beginners C-course.

Here was mine. For further discussions feel free to contact me
via email. I'll be doing a beginner's course in C from November
on ;-)

- Jochen

--
--
Jochen Schoof   (http://www-info2.informatik.uni-wuerzburg.de/staff/joscho)
___________________________________________________________________________
\_Address __/  Informatik II, Uni Wuerzburg, Am Hubland, D-97074 Wuerzburg



Sun, 28 Mar 1999 03:00:00 GMT  
 Why cast malloc's return?

Quote:

> :     p      = malloc(sizeof(p[0])*nitems);
<snip>
> I think p[0] should be replaced by *p in this context. I am
> not sure whether using p[0] can result in undefined behaviour.
> Pointer arithmetic is only allowed in the range of existing
> data blocks and you don't have any data block here. However
> the main question is: Is p[0] pointer arithmetic or not. I
> myself would be very interested in an answer to that.

The question is too subtle for me. Nothing within a sizeof is
executed, the expression is only parsed for its type. Thus, as long as
the expression parses correctly: and I think p[0] does, it is allowed
inside a sizeof.

I use *p because of habit (and maybe because of two less keystrokes?
:-) but I would be very surprised if p[0] were invalid.

Cheers
Tanmoy
--

Tanmoy Bhattacharya O:T-8(MS B285)LANL,NM87545 H:#9,3000,Trinity Drive,NM87544
Others see <gopher://yaleinfo.yale.edu:7700/00/Internet-People/internet-mail>,
<http://alpha.acast.nova.edu/cgi-bin/inmgq.pl>or<ftp://csd4.csd.uwm.edu/pub/
internetwork-mail-guide>. -- <http://nqcd.lanl.gov/people/tanmoy/tanmoy.html>
fax: 1 (505) 665 3003   voice: 1 (505) 665 4733    [ Home: 1 (505) 662 5596 ]



Sun, 28 Mar 1999 03:00:00 GMT  
 Why cast malloc's return?



Quote:

>> :     p      = malloc(sizeof(p[0])*nitems);
><snip>
>> I think p[0] should be replaced by *p in this context. I am
>> not sure whether using p[0] can result in undefined behaviour.
>> Pointer arithmetic is only allowed in the range of existing
>> data blocks and you don't have any data block here. However
>> the main question is: Is p[0] pointer arithmetic or not. I
>> myself would be very interested in an answer to that.

>The question is too subtle for me. Nothing within a sizeof is
>executed, the expression is only parsed for its type. Thus, as long as
>the expression parses correctly: and I think p[0] does, it is allowed
>inside a sizeof.

>I use *p because of habit (and maybe because of two less keystrokes?
>:-) but I would be very surprised if p[0] were invalid.

p[0] and *p are equivalent by definition:

p[0] == *(p + 0) == *p

I would not use either of these anyway, because it can easily be avoided:
just use the appropriate type expression which has the same type as *p, for
example:

        char **vec = malloc(sizeof (char *) * 128);

rather than

        char **vec = malloc(sizeof *vec * 128);

Then you don't have to worry about your pointer arithmetic generating invalid
pointers. I'd tend to say that even if you evaluate an expression for the type
attribute only, the rules are still the rules. C's rules about pointer
arithmetic are decoupled from the issue of pointer dereferencing.  Even if you
don't ever dereference the pointer, you may not aim it past one element beyond
the end of the object.

Sometimes it's cleaner to take the size of an actual object. The type
expression which gives the same time may be verbose, plus using a type
expression requires those pesky parentheses which are not required if your
object is designated by a unary expression. For instance, I would sooner write:

        sizeof addr;

than

        sizeof (struct sockaddr_in);

less typing, clearer intent.



Sun, 28 Mar 1999 03:00:00 GMT  
 Why cast malloc's return?

<snip>

Quote:
> >> :     p      = malloc(sizeof(p[0])*nitems);
<<snip>
> >The question is too subtle for me. Nothing within a sizeof is
> >executed, the expression is only parsed for its type. Thus, as long as
> >the expression parses correctly: and I think p[0] does, it is allowed
> >inside a sizeof.

> >I use *p because of habit (and maybe because of two less keystrokes?
> >:-) but I would be very surprised if p[0] were invalid.

> p[0] and *p are equivalent by definition:

> p[0] == *(p + 0) == *p

Agreed.

Quote:

> I would not use either of these anyway, because it can easily be avoided:
> just use the appropriate type expression which has the same type as *p, for
> example:

>         char **vec = malloc(sizeof (char *) * 128);

> rather than

>         char **vec = malloc(sizeof *vec * 128);

I have a very strong preference for the second form because the first
form is more error-prone. I sometimes need to change an `int *' to a
`long *', and hardwired type names in the code are bad. I try to
follow the rule that the same information should not be repeated in
the code: if I change the declaration, my code should automagically
acquire all dependent changes. Even though it is impossible to achieve
this ideal, one can try to do as much is posible. This principle has
stood me in good stead in the past, and I strongly recommend it.

Quote:

> Then you don't have to worry about your pointer arithmetic generating invalid
> pointers. I'd tend to say that even if you evaluate an expression for the type

I am not worried! The quote from my post above simply referred to my
amazement that anyone would be worried. In any case, whoever said
`evaluate'? The standard explicitly states that the expression is not
`evaluated'. I said `parsed'.

Quote:
> attribute only, the rules are still the rules. C's rules about pointer
> arithmetic are decoupled from the issue of pointer dereferencing.  Even if you
> don't ever dereference the pointer, you may not aim it past one element beyond
> the end of the object.

No one claimed otherwise.

If the sizeof expression (including the + or [] operator) is not
evaluated, how am I ever `aiming a pointer past one element beyond the
end of the object'? How am I ever dereferencing it if the * is not
executed?

In fact because the operand is not evaluated, an uninitialized object
used here does not use the `value' of the object: so, use of vec on
the rhs of your example is not undefined due to that clause either.

And, finally, if more evidence were needed, even though examples are
not normative, they do express intent. From the example 1 in 6.3.3.4:

extern void *alloc(size_t);
double *dp = alloc(sizeof *dp);

Cheers
Tanmoy

--

Tanmoy Bhattacharya O:T-8(MS B285)LANL,NM87545 H:#9,3000,Trinity Drive,NM87544
Others see <gopher://yaleinfo.yale.edu:7700/00/Internet-People/internet-mail>,
<http://alpha.acast.nova.edu/cgi-bin/inmgq.pl>or<ftp://csd4.csd.uwm.edu/pub/
internetwork-mail-guide>. -- <http://nqcd.lanl.gov/people/tanmoy/tanmoy.html>
fax: 1 (505) 665 3003   voice: 1 (505) 665 4733    [ Home: 1 (505) 662 5596 ]



Sun, 28 Mar 1999 03:00:00 GMT  
 Why cast malloc's return?



Quote:
>I would not use either of these anyway, because it can easily be avoided:
>just use the appropriate type expression which has the same type as *p, for
>example:

>        char **vec = malloc(sizeof (char *) * 128);

>rather than

>        char **vec = malloc(sizeof *vec * 128);

This second form is much better style. It is much easier to verify as
being correct since you don't have to refer to other parts of the code
and you're less likely to get it wrong in the first place.

Quote:
>Then you don't have to worry about your pointer arithmetic generating invalid
>pointers.

This is a non-issue. sizeof doesn't evaluate its operand, it simply
determines its type and the size of that type.

#include <stdlib.h>

char a[10];

sizeof(1/0)
sizeof *(char*)0
sizeof *(char*)rand()
sizeof a[11]

are all valid - the first evaluates to the same as sizeof(int) and the
last 3 evaluate to 1.

Quote:
>I'd tend to say that even if you evaluate an expression for the type
>attribute only, the rules are still the rules.

Standard section 6.3.3.4 The sizeof operator:

"The size is determined from the type of the operand which is not itself
 evaluated"

--
-----------------------------------------


-----------------------------------------



Sun, 28 Mar 1999 03:00:00 GMT  
 Why cast malloc's return?

 > >         char **vec = malloc(sizeof (char *) * 128);
 > > rather than
 > >         char **vec = malloc(sizeof *vec * 128);
 >
 > I have a very strong preference for the second form because the first
 > form is more error-prone.

Indeed.  The more so if declaration and initialization are separated by
many lines of code.
--
dik t. winter, cwi, kruislaan 413, 1098 sj  amsterdam, nederland, +31205924131
home: bovenover 215, 1025 jn  amsterdam, nederland; http://www.cwi.nl/~dik/



Mon, 29 Mar 1999 03:00:00 GMT  
 Why cast malloc's return?




: >
: >> :     p      = malloc(sizeof(p[0])*nitems);
: ><snip>
: >> I think p[0] should be replaced by *p in this context. I am
: >> not sure whether using p[0] can result in undefined behaviour.
: >> Pointer arithmetic is only allowed in the range of existing
: >> data blocks and you don't have any data block here. However
: >> the main question is: Is p[0] pointer arithmetic or not. I
: >> myself would be very interested in an answer to that.
: >
: >The question is too subtle for me. Nothing within a sizeof is
: >executed, the expression is only parsed for its type. Thus, as long as
: >the expression parses correctly: and I think p[0] does, it is allowed
: >inside a sizeof.
: >
: >I use *p because of habit (and maybe because of two less keystrokes?
: >:-) but I would be very surprised if p[0] were invalid.

Of course I'd be surprised, too. My question certainly had a somehow
philosophic touch :-)  Actually I never though of using p[0] in the
given context and when reading it started thinking about it. But I think
Tanmoy is right to point out, that the argument to sizeof is not
evaluated but only parsed for its type. The saved keystrokes will keep
me using *p anyway ;-)

: p[0] and *p are equivalent by definition:
:
: p[0] == *(p + 0) == *p

This is of course correct.

: I would not use either of these anyway, because it can easily be avoided:
: just use the appropriate type expression which has the same type as *p, for
: example:

[Example and comment deleted.]

As has been pointed out in some followups, your code will be far better
maintainable if you use the object itself.

- Jochen

--
--
Jochen Schoof   (http://www-info2.informatik.uni-wuerzburg.de/staff/joscho)
___________________________________________________________________________
\_Address __/  Informatik II, Uni Wuerzburg, Am Hubland, D-97074 Wuerzburg



Mon, 29 Mar 1999 03:00:00 GMT  
 
 [ 9 post ] 

 Relevant Pages 

1. casting return value from malloc

2. (void *) & casting the pointer returned by malloc

3. Why not cast the rerurn from malloc()?

4. Why not cast malloc?

5. Why cast a void return?

6. malloc: to cast or not to cast

7. Non-return of static local malloc'd variable

8. why aren't cast expressions lvalvues?

9. Why can't overload type cast to base type (object)

10. Why isn't malloc necessary here?

11. Cant see why malloc() req'd.

12. malloc vs 'no-malloc' - help

 

 
Powered by phpBB® Forum Software