8

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?

Kevin Panko
  • 8,356
  • 19
  • 50
  • 61
Abhinav Gauniyal
  • 7,034
  • 7
  • 50
  • 93
  • 4
    "Can any "TYPE" of pointer can point to any other type?" No. – juanchopanza Oct 31 '13 at 15:30
  • 2
    `Can any "TYPE" of pointer can point to any other type?` is a question, not a statement – Paddyd Oct 31 '13 at 15:31
  • 3
    Seems like you understand fairly well. If you cast a pointer's type, then you can assign any pointer to point to any address, but the results may be incorrect. – Kevin Panko Oct 31 '13 at 15:35
  • Yeah actually this was an statement , an answer infact , here see the comment : http://stackoverflow.com/a/8530093/2648679 – Abhinav Gauniyal Oct 31 '13 at 15:35
  • 3
    Why the downvote? That s actually a good question. – DrakaSAN Oct 31 '13 at 15:36
  • If i point a pointer first to a char type and then to a int type. 1. Is this possible? 2. Will it lead to any errors? Consider i am just abandoning first variable. – Abhinav Gauniyal Oct 31 '13 at 15:37
  • 2
    Note that the size of an `int` varies from system to system. 4 bytes is actually more common these days. – Keith Thompson Oct 31 '13 at 15:38
  • 4
    I'm not sure why people are voting to close this. I'd say it's a question about programming, specifically about pointer semantics. – Keith Thompson Oct 31 '13 at 15:44
  • You can always cast it, but when you access it, it may result in undefined behavior, wrong result, or even segmentation fault. – SwiftMango Oct 31 '13 at 15:47
  • And without casting? i mean is it possible to point a char* pointer to int type variable? As pointers are theoretically considered to contain addresses only , and that dosent changes with change in data type? – Abhinav Gauniyal Oct 31 '13 at 15:57
  • The Standard makes no such claim that the address pointed to will not change when you cast from one type to another type. In fact you can prove this to yourself (that they might change) by `static_cast`ing a pointer from a base type to a derived type and `cout`ing the resulting pointers. – John Dibling Oct 31 '13 at 16:09
  • @AbhinavGauniyal that question can be answered by writing some code to see if it works – Kevin Panko Oct 31 '13 at 16:09
  • 1
    @KevinPanko: Questions like this can only be *partially* answered by writing some code to see if it works. There are a lot of things that happen to work on many or most systems, but whose behavior is not defined by the language. – Keith Thompson Oct 31 '13 at 21:59

5 Answers5

7

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, an int 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.

abelenky
  • 63,815
  • 23
  • 109
  • 159
  • I strongly doubt that on any given platform, casting a pointer from one type to another will modify the address value. I understand that dereferencing an unaligned pointer may cause an exception, but I doubt the compiler would align the pointer when the cast is done. I can't see any benefits or any motive for this behavior. – Spidey Oct 31 '13 at 15:46
  • Are pointers treated differently? while being the fact that all pointers irrespectively of their types are used just to store memory address of that location? or does those memory adress differ with the types? – Abhinav Gauniyal Oct 31 '13 at 15:48
  • I can certainly design a machine where all chars are stored in a 16-bit address space, ints are stored in a different, 24-bit address space, other types are stored in a separate 32-bit address space, and executable code is in a 64-bit address space. Such a design would be perfectly legal from a C++ standpoint, and the various pointers would be completely incompatible with each other. – abelenky Oct 31 '13 at 15:57
  • 4
    This takes me back to days of writing my homework programs on my Intel computer, and seeing everything work fine, only to find the program would crash on the professor's unix workstation. – Kevin Panko Oct 31 '13 at 16:31
  • Yeah, first time I ran into alignment problems on a non-Intel platform, I was absolutely flabbergasted and blocked for days. Now its almost second-nature to recognize them. :) – abelenky Oct 31 '13 at 16:36
4

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 a void* 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* to bar* and back to foo* 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 type bar, but (a) it's usually a bad idea, and (b) in some cases, it may not work (say, if the target types foo and bar have different sizes or alignment requirements).

You can get away with things like:

int n = 42;
char *p = (char*)&n;

which causes p to point to n -- but then *p doesn't give you the value of n, it gives you the value of the first byte of n as a char.

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 an int 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.)

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • 1
    @JohnDibling the cast is valid. `char*` can alias any other pointer type. – Simple Oct 31 '13 at 16:34
  • 1
    @Simple: You're right, I take it all back. Lack of sleep leads to great confusion. – John Dibling Oct 31 '13 at 16:51
  • @Simple Except for function pointers. Function pointers may actually be larger than normal `char*`, as seen on the PPC platform, and thus cannot be interchangeable with normal pointers. – cmaster - reinstate monica Jun 18 '19 at 20:01
  • @cmaster: Right. There's also some controversy about whether conversions between `void*` and function pointers is even permitted. (In my opinion, it is but it has undefined behavior.) But at the very least, converting a function pointer to `void*` can lose information. – Keith Thompson Jun 18 '19 at 20:53
3

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 a float* pointer, then you'll probably get useless results (unless you've programmed it that way for a specific reason). This is because an int is stored in memory differently from the way a float is stored.

Peter Bloomfield
  • 5,578
  • 26
  • 37
  • If i am not performing an iteration event or even not declaring an array so the compiler might predict that , will it still give error when i use same pointer to point first to an Int and then abandon it , and then point to char next time. As i think that pointer just stores the address only and that should not get modified with change of var data types? – Abhinav Gauniyal Oct 31 '13 at 15:51
  • Your compiler will likely issue an error or warning if you try to assign the wrong type to a pointer; e.g. if you try to assign the address of an `int` into a `char*` pointer. You can override the error/warning by using `reinterpret_cast<>()`. There are some situations where that's necessary, but it's definitely not something you should be doing in most programs. – Peter Bloomfield Oct 31 '13 at 16:22
1

Can any "TYPE" of pointer can point to any other type?

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 a static_cast, the reinterpret_cast is invalid. Hence you can't do Foo* foo = ...; Bar* bar = (Bar*)foo; unless Foo and Bar are actually related.

You can also use reinterpret_cast to cast from an object pointer to a void* and vice versa, and in that sense a void* 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 a char* 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 a char, 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 a Foo when the thing it actually points to is a Bar yields Undefined Behavior when the types are not related. You would do well to avoid these types of casts at all costs.

John Dibling
  • 99,718
  • 31
  • 186
  • 324
  • If i somehow point a pointer first to int and then abandon that variable and point the same pointer to another char variable , i dont know if this is possible , but i dont think it should produce an error , because pointers are meant to store addresses and i think type just signifies the arithmetic operation performed on them. Am i right somewhere sir? – Abhinav Gauniyal Oct 31 '13 at 15:43
  • 2
    @AbhinavGauniyal: You can do pointer math on a `char*` that actually points to an `int`, but if you use that pointer and it doesnt point to something that's actually a `char`, you'll get undefined behavior. – John Dibling Oct 31 '13 at 15:50
  • The `char*` had to originate by actually pointing at a `char`. That's the bottom line. – John Dibling Oct 31 '13 at 16:04
1

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.

Aside: Function pointers on PPC

On the PPC platform, this was quite obvious: A function pointer was actually two pointers under the hood, so there was simply no way to meaningfully cast a function pointer to a data pointer or back. I.e. the following would hold:

int* dataP;
int (*functionP)(int);

assert(sizeof(dataP) == 4);
assert(sizeof(functionP) == 8);
assert(sizeof(dataP) != sizeof(functionP));

//impossible:
//dataP = (int*)functionP;          //would loose information
//functionP = (int (*)(int))dataP;  //part of the resulting pointer would be garbage

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:

char a[4];
int* alias = (int*)a;
//int foo = *alias;    //may crash because alias is not aligned properly

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:

char* a = malloc(sizeof(int));
int* alias = (int*)a;
*alias = 0;    //perfectly legal, the pointer is aligned

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:

assert(sizeof(float) == sizeof(uint32_t));
float foo = 42;
//uint32_t bits = *(uint32_t*)&foo;    //type punning is illegal

If you absolutely must reinterpret a bit pattern as another type, you must use memcpy():

assert(sizeof(float) == sizeof(uint32_t));
float foo = 42;
uint32_t bits;
memcpy(&bits, &foo, sizeof(bits));    //bit pattern reinterpretation is legal when copying the data

To allow memcpy() and friends to actually be implementable, the C/C++ language standards provide for an exception for char types: You can cast any pointer to a char*, copy the char 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.

Community
  • 1
  • 1
cmaster - reinstate monica
  • 38,891
  • 9
  • 62
  • 106