Is this statement correct? Can any "TYPE" of pointer can point to any other type? Because I believe so, still have doubts.
Why are pointers declared for definite types? E.g. int
or char
?
The one explanation I could get was: if an int
type pointer was pointing to a char
array, then when the pointer is incremented, the pointer will jump from 0 position to the 2 position, skipping 1 position in between (because int size=2).
And maybe because a pointer just holds the address of a value, not the value itself, i.e. the int
or double
.
Am I wrong? Was that statement correct?
Some pointers are more equal than others...
First of all, not all pointers are necessarily the same thing. Function pointers can be something very different from data pointers, for instance.
Alignment
Furthermore, there is problems with alignment: Depending on the platform some data types may need to be aligned in memory. This is especially common with vector data types, but could apply to any type larger than a byte. For instance, if an
int
must be 4 byte aligned, the following code might crash:This is not an issue if the pointer comes from a
malloc()
call, as that is guaranteed to return sufficiently aligned pointers for all types:Strict aliasing and type punning
Finally, there are strict aliasing rules: You must not access an object of one type through a pointer to another type. Type punning is forbidden:
If you absolutely must reinterpret a bit pattern as another type, you must use
memcpy()
:To allow
memcpy()
and friends to actually be implementable, the C/C++ language standards provide for an exception forchar
types: You can cast any pointer to achar*
, copy thechar
data over to another buffer, and then access that other buffer as some other type. The results are implementation defined, but the standards allow it. Use cases are mostly general data manipulation routines like I/O, etc.TL;DR:
Pointers are much less interchangeable than you think. Don't reinterpret pointers in any other way than to/from
char*
(check alignment in the "from" case). And even that does not work for function pointers.Pointers may be interchangeable, but are not required to be.
In particular, on some platforms, certain types need to be aligned to certain byte-boundaries. So while a
char
may be anywhere in memory, anint
may need to be on a 4-byte boundary.Another important potential difference is with function-pointers.
Pointers to functions may not be interchangeable with pointers to data-types on many platforms.
It bears repeating: This is platform-specific.
I believe Intel x86 architectures treat all pointers the same.
But you may well encounter other platforms where this is not true.
Any pointer can refer to any location in memory, so technically the statement is correct. With that said, you need to be careful when reinterpreting pointer types.
A pointer basically has two pieces of information: a memory location, and the type it expects to find there. The memory location could be anything. It could be the location where an object or value is stored; it could be in the middle of a string of text; or it could just be an arbitrary block of uninitialised memory.
The type information in a pointer is important though. The array and pointer arithmetic explanation in your question is correct -- if you try to iterate over data in memory using a pointer, then the type needs to be correct, otherwise you may not iterate correctly. This is because different types have different sizes, and may be aligned differently.
The type is also important in terms of how data is handled in your program. For example, if you have an
int
stored in memory, but you access it by dereferencing afloat*
pointer, then you'll probably get useless results (unless you've programmed it that way for a specific reason). This is because anint
is stored in memory differently from the way afloat
is stored.Generally no. The types have to be related.
It is possible to use
reinterpret_cast
to cast a pointer from one type to another, but unless those pointers can be converted legally using astatic_cast
, thereinterpret_cast
is invalid. Hence you can't doFoo* foo = ...; Bar* bar = (Bar*)foo;
unlessFoo
andBar
are actually related.You can also use
reinterpret_cast
to cast from an object pointer to avoid*
and vice versa, and in that sense avoid*
can point to anything -- but that's not what you seem to be asking about.Further you can
reinterpret_cast
from object pointer to integral value and vice versa, but again, not what you appear to be asking.Finally, a special exception is made for
char*
. You can initialize achar*
variable with the address of any other type, and perform pointer math on the resulting pointer. You still can't dereference thru the pointer if the thing being pointed to isn't actually achar
, but it can then be casted back to the actual type and used that way.Also keep in mind that every time you use
reinterpret_cast
in any context, you are dancing on the precipice of a cliff. Dereferencing a pointer to aFoo
when the thing it actually points to is aBar
yields Undefined Behavior when the types are not related. You would do well to avoid these types of casts at all costs.Every pointer is of some specific type. There's a special generic pointer type
void*
that can point to any object type, but you have to convert avoid*
to some specific pointer type before you can dereference it. (I'm ignoring function pointer types.)You can convert a pointer value from one pointer type to another. In most cases, converting a pointer from
foo*
tobar*
and back tofoo*
will yield the original value -- but that's not actually guaranteed in all cases.You can cause a pointer of type
foo*
to point to an object of typebar
, but (a) it's usually a bad idea, and (b) in some cases, it may not work (say, if the target typesfoo
andbar
have different sizes or alignment requirements).You can get away with things like:
which causes
p
to point ton
-- but then*p
doesn't give you the value ofn
, it gives you the value of the first byte ofn
as achar
.The differing behavior of pointer arithmetic is only part of the reason for having different pointer types. It's mostly about type safety. If you have a pointer of type
int*
, you can be reasonably sure (unless you've done something unsafe) that it actually points to anint
object. And if you try to treat it as an object of a different type, the compiler will likely complain about it.Basically, we have distinct pointer types for the same reasons we have other distinct types: so we can keep track of what kind of value is stored in each object, with help from the compiler.
(There have been languages that only have untyped generic pointers. In such a language, it's more difficult to avoid type errors, such as storing a value of one type and accidentally accessing it as if it were of another type.)