user1762571
user1762571

Reputation: 1949

Difference between different ways of malloc

struct node{
  int w;
  int x;
}
struct node *item;
  1. Please explain the difference between these statements.
  2. 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

Answers (4)

M.M
M.M

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

John Bode
John Bode

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.


1 - Prior to the C89 standard, 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

chqrlie
chqrlie

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

wolfPack88
wolfPack88

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

Related Questions