I know that I can protect myself by writing
int *ptr = malloc(sizeof (*ptr))
instead of
int *ptr = malloc(sizeof (int))
The benefit is that if you decide to change the type of ptr
to for instance long*
instead of int*
, then you only need to change the code at one place.
My question is, is this strategy always safe to do? Is there any situation where the construct T *ptr = malloc(sizeof(*ptr))
would not work? Does it matter if T
is some complex struct, pointer to pointer, function pointer or an array? Or a combination of them for that matter.
I have tried to come up with a situation where it causes problems, but to me it seems safe. But I want to be able to trust the code completely.
The only case I could see causing problems is if *ptr
has a variable-length array type, because that's the only case where sizeof
evaluates its operand.
That is:
int n = ...;
T (*ptr)[n] = malloc(sizeof *ptr);
has undefined behavior because the type of *ptr
is T [n]
, which is a variable-length array type, which means sizeof
evaluates its operand, which dereferences an uninitialized pointer (*ptr
).
However, it's hard to run into that issue by accident. Normally you'd just do
T *ptr = malloc(n * sizeof *ptr);
which is fine1.
1 Well, the multiplication might overflow. To protect against that, you need something like T *ptr = calloc(n, sizeof *ptr);
.