Reputation: 1949
struct node{
int w;
int x;
}
struct node *item;
i read as typecasting after malloc is not needed. why is that so?
1) item = malloc(sizeof(*item));
2) item = malloc(sizeof(struct node));
3) item = (struct node *) malloc(sizeof(struct node));
Upvotes: 1
Views: 639
Reputation: 141648
Form 2 is bad because you may accidentally allocate the wrong amount of memory.
Form 1 and Form 3 both allow the programmer to do a visual check that allocation is correct:
item = malloc(sizeof(*item));
// ^^^^ ^^^^^
item = (struct node *) malloc(sizeof(struct node));
// ^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^
Once you learn that varname
should go with *varname
, or that (Typename *)
should go with (Typename)
, then you are more likely to quickly detect size errors.
As explained on the main thread about this, in C89 Form 3 was dangerous whereas Form 1 was safe. In C99 and later that rationale is less compelling, however Form 1 has the benefits of being more compact, and requiring less maintenance. If the type of item
is changed then any Form 3 lines will trigger a compilation error, whereas Form 1 lines will just automatically work correctly with the updated type.
Upvotes: 1
Reputation: 123598
Functionally, all three are equivalent.
Stylistically, 1 is the preferred option (at least by me and a number of other C programmers). Note that sizeof
is an operator, not a function, and parentheses are only required when the operand is a type name. So you could write sizeof *item
as opposed to sizeof (*item)
- the parens don't hurt anything except readability. Also note that sizeof
does not attempt to evaluate its argument (it won't try to dereference item
); all it does is compute the number of bytes required by the resulting type, and it does that at compile time, not run time.
As far as C is concerned, you should not cast the result of malloc
. As of the 1989 standard it's no longer necessary; malloc
returns a void *
, which can be assigned to any other pointer type without needing an explicit cast1.
Under the C89 standard, casting the result of malloc
could suppress a useful diagnostic if you forgot to include stdlib.h
or otherwise didn't have a declaration for malloc
in scope. C89 still allowed implicit int
declarations; if the compiler saw a function call in the code without a declaration, it assumed the function returned an int
value. If you left off the cast, the compiler would complain that you were trying to assign an integer value to a pointer object. With the cast, the compiler would compile the code without a diagnostic, but you'd be converting a pointer value to an int
and back to a pointer again, which may or may not work.
The C99 standard got rid of implicit int
declarations, so that isn't a problem anymore; cast or not, you'll get a diagnostic if you forget to include stdlib.h
. You should still leave the cast off for readability and maintainability reasons; all it does is add useless visual clutter. If you change the declaration of the target (from struct foo *
to struct bar *
), then you'd have to update the cast as well, which is just extra work, and if you forget to do it then it's a bug. item = malloc( sizeof *item )
will always do the right thing without any further maintenance, no matter what changes you make to the type of item
.
C++, being a different language from C with different rules, does not allow you to assign a void *
to another pointer type without an explicit cast, so you would have to cast the result of malloc
in that case. This is an issue if you're migrating from C to C++ and haven't redone all your dynamic memory management code (which is the only excuse for using malloc
in C++ code). As a matter of course, you should not use malloc
/calloc
/realloc
in C++; either use one of the standard containers, or use the new
operator.
malloc
, calloc
, and realloc
all returned char *
, so a cast was required if the target was a different pointer type. Unfortunately, the habit persisted even though it was no longer necessary
Upvotes: 2
Reputation: 145307
Let's look at these:
1) item = malloc(sizeof(*item));
The above code is the classic way in C. It may be safer to use calloc
as it will clear to allocated structure to all bits zero. A useful side effect that will save you if you later add fields to the structure and forget to initialize the in the code that follows the malloc
in every instance of an allocation. I would so recommend:
1 preferred) item = calloc(1, sizeof(*item));
The alternative below assumes item
is a pointer to struct node
. It may be true when you first write the code and may become false if you later change the type of item
or if you copy to code to a different place where item
is a different type and you forget to make the change.
2) item = malloc(sizeof(struct node));
The last option exhibits another issue:
3) item = (struct node *) malloc(sizeof(struct node));
The issue of casting the return value of malloc
has been commented a lot elsewhere. It is necessary in C++ and considered useless and potentially error prone in C. There is a context in which it may actually serve a good purpose:
#define alloc_node() ((struct node*)calloc(1, sizeof(node)))
item = alloc_node();
Here it is advisable to use the cast in order to detect allocations of the wrong type. If item
is not a pointer to a struct node
, the compiler will complain and prevent the bug.
In conclusion, prefer calloc
over malloc
, and prefer sizeof(*item)
over sizeof(node node)
. If the context does not allow to use sizeof(*dst)
, as above or within an expression or a function argument, then use the cast.
Upvotes: 2
Reputation: 4203
All methods will give you exactly the same result in this particular case.
1:
item = malloc(sizeof(*item));
*item
is a struct node
, therefore sizeof(*item)
will return the size of a struct node
, and the line will allocate memory for a single node. This is sometimes to be preferred to 2), as if you were to refactor item
to be a different type, you do not need to change this line.
2:
item = malloc(sizeof(struct node));
This line is fairly self-explanatory. As mentioned before, though, if item
were to change type, you would need to change this line as the amount of memory allocated will no longer be correct (except, perhaps, by pure luck).
3:
malloc
returns a pointer to void
, or void *
. This is automatically converted to the proper type even without a cast. In fact, several people (myself included) will advise you strongly not to use the typecast ever. For more details, read the accepted answer to this question
Upvotes: 2