The thing to remember about sizeof
is that it is a compile-time operator1; it returns the number of bytes based on the type of the operand.
The type of arr
is int [24]
, so sizeof arr
will evaluate to the number of bytes required to store 24 int
values. The type of ptr
is int *
, so sizeof ptr
will evaluate to the number of bytes required to store a single int *
value. Since this happens at compile time, there's no way for sizeof
to know what block of memory ptr
is pointing to or how large it is.
In general, you cannot determine how large a chunk of memory a pointer points to based on the pointer value itself; that information must be tracked separately.
Stylistic nit: a preferred way to write the malloc
call is
int *ptr = malloc(sizeof *ptr * N);
In C, you do not need to cast the result of malloc
to the target pointer type2, and doing so can potentially mask a useful diagnostic if you forget to include stdlib.h
or otherwise don't have a prototype for malloc
in scope.
Secondly, notice that I pass the expression *ptr
as the operand to sizeof
rather than (int)
. This minimizes bugs in the event you change the type of ptr
but forget to change the type in the corresponding malloc
call. This works because sizeof
doesn't attempt to evaluate the operand (meaning it doesn't attempt to dereference ptr
); it only computes its type.
1 The exception to this rule occurs when
sizeof
is applied to a variable-length array; since the size of the array isn't determined until runtime, a
sizeof
operator applied to a VLA will be evaluated at runtime.
2 Note that this is
not the case in C++; a cast is required, but if you're writing C++ you should be using
new
and
delete
instead of
malloc
and
free
anyway. Also, this is only true since C89; older versions of C had
malloc
return
char *
instead of
void *
, so for those versions the cast
was required. Unless you are working on a
very old implementation (such as an old VAX mini running an ancient version of VMS), this shouldn't be an issue.