How To Cast The Result Of malloc
Updated:
A question that often arises when allocating a new block of memory in C is: should I cast the result of malloc or not?
Let’s take an example.
Allocating an array
We want to dynamically allocate an array of floats called samples. So we need to declare a pointer variable that will point to the base address of this array.
With an explicit cast we would write:
float *samples = (float *) malloc(sizeof(*samples) * number_of_samples);
Without the explicit cast operation we would write:
float *samples = malloc(sizeof(*samples) * number_of_samples);
Later we will discuss the content of the argument of malloc(), but for now let us ask ourselves: which of the two versions should I use?
Let’s start by saying that both versions are correct in C, but most experienced programmers prefer the method without casting, the second one.
A different case is whether you have to compile a piece of C code as C++, in which case the explicit cast operation is mandatory and there is no room for discussion.
The point is that in C malloc returns a void pointer, and a void pointer is automatically and safely promoted to any other pointer type. So it might seem like it’s just superfluous. In reality, we can think more deeply and analyze the two cases to understand why the second is the most adopted.
So, what are the advantages and disadvantages in C for casting the result of malloc or not?
To cast or not to cast
Why you might want to cast:
- To make your code more portable between C and C++.
- To help the developer identify inconsistencies in type sizing (so we are talking about the argument of
malloc). This can especially help when the pointer is declared far from themalloccall. - To nudge the developer for extra verification in mind.
Why you don’t want to cast:
- The cast from a void pointer is redundant, unnecessary.
- It produces repetitions, which is generally not a good thing in coding.
- When you cast, you may hide an error if you forgot to include
stdlib.h, in which the prototype formallocis found. When the compiler cannot find the prototype ofmalloc, as for the C standard, it assumes thatmallocreturns anint. This is an implicit function declaration. Now, if a function returns anintand we try to store thatintin a pointer we get a warning from the compiler. Instead with the cast this warning is not produced, thus masking a bug. - If you change the the type of the pointer in its declaration you also need to change all the explicit casts where
mallocis called. Obviously, there’s no need if you don’t cast.
The argument of malloc
A final thought on the argument that we pass to malloc().
float *samples = malloc(sizeof(*samples) * number_of_samples);
We need to calculate the size of memory needed to store all the samples, so we multiply the number of samples by the size in memory of each sample. And so far nothing strange.
There are actually two details that can be overlooked.
-
The size of each sample is coded as
sizeof(*samples)and not assizeof(float). Usingsizeof(float)the code needlessly repeats the type information (float) and this can cause errors. It’s better to de-reference the pointer used to store the return value ofmalloc, so we’ll use*samples. This way this size is locked in thesamplesdeclaration, so we satisfy the good habit of “only a place to make changes”. -
The order of the multiplication operands should not be overlooked either. While moving
number_of_samplesto the front may increase your attention on this variable, keeping thesizeoffirst ensures multiplication is done with at leastsize_tmath. In fact, this multiplication may overflow if we putnumber_of_samplesfirst and its type was smaller thansize_t. So, it’s safer to putsizeoffirst.