There’s nothing magic about pointer types - a pointer has a size like any other object type1, so it’s just as valid to use sizeof (char *)
as sizeof (char)
.
Pointer type sizes are as big as the implementation needs them to be, and different pointer types may have different sizes2. Similarly, the internal representation of pointer types can vary among implementations.
Remember that sizeof
is an operator, not a function; parens are only required if the operand is a type name. Also, unless its operand is a variable-length array, sizeof
expressions are evaluated at compile time, not runtime. Similarly, sizeof
only cares about the type of its operand, not its value or how it’s stored. You can use sizeof
on expressions as well as type names - a common idiom for malloc
is
T *p = malloc( N * sizeof *p ); // for any type T
The expression *p
has type T
, so sizeof *p == sizeof (T)
.
void
is an incomplete type that cannot be completed - you cannot create an object of void
type and strictly speaking the type has no size. You can, however, create an object of void *
type, and its size and alignment will be the same as char *
. A void *
is a "generic" pointer type and can be converted to other pointer types without an explicit cast. Since there's no such thing as a void
object, you cannot dereference a void *
- you have to convert it to another pointer type first.
- On common platforms like x86 all pointer types have the same size, but that’s not required.