-1

If I declare

int x = 5 ;
int* p = &x;
unsigned int y = 10 ;
cout << p+y ;

Is this a valid thing to do in C++, and if not, why?

It has no practical use, but is it possible?

jogojapan
  • 68,383
  • 11
  • 101
  • 131
abkds
  • 1,764
  • 7
  • 27
  • 43
  • 4
    Integers are not pointers. Pointers are not integers. – Cat Plus Plus Jul 17 '13 at 00:25
  • 2
    "A pointer is basically an unsigned integer." No, it's not. Pointer and integer are completely different abstractions. The underlying representation is irrelevant (and bitwise casting is evil so don't even think about it). –  Jul 17 '13 at 00:25
  • Yes i understand that , i am saying that isn't pointer a unsgined integer value – abkds Jul 17 '13 at 00:28
  • 2
    @aaronman: in what way are pointers (I guess you mean references) more closely related in Java? Or are you just being unnecessarily rude to a beginner? – Grokys Jul 17 '13 at 00:28
  • @Groky I am being rude, but the implication in my joke was that the user wasn't ready for c++, sorry if I offended you or him – aaronman Jul 17 '13 at 00:30
  • 3
    @aaronman In that case, at least suggest something _sane_, like C#. :3 –  Jul 17 '13 at 00:30
  • 1
    The only guarantee is that pointers sort of behave like integers when addressing contiguous arrays in memory. Beyond that, they need not be integers at all - they could be *anything* (files, URL's, bananas, etc..), they are an abstraction of the memory model of the underlying hardware. – Thomas Jul 17 '13 at 00:31
  • 1
    @digi_abhshk If you consider the fact that memory addresses start at 0 and go up from there, yes. But unless your unsigned integers are the same size as your memory addresses, no, not really. – 2rs2ts Jul 17 '13 at 00:31
  • Your example actually says, "Take the pointer `p`, increment the address it refers to by `10` times the size of whatever `p` points to, then print that address to the standard output. Not a horribly unusual request. – lurker Jul 17 '13 at 00:32
  • @Thomas They can't be anything. They can be only pointers. –  Jul 17 '13 at 00:32
  • @aaronman: Nobody is *ready* for C++! (no offence taken, but you were in that situation once upon a time) – Grokys Jul 17 '13 at 00:32
  • @rightfold this site might be a bit c# centric, java is used by many big companies heavily – aaronman Jul 17 '13 at 00:32
  • @Groky oh trust me I know, I used to just throw `*`'s and `&`'s until it worked – aaronman Jul 17 '13 at 00:33
  • @rightfold Sigh.. yes, an X is an X, well done. What I mean is, *they could be an abstraction for anything*, the memory model of the hardware need not be a bunch of bits addressed by an offset, it could potentially be anything, so using pointers under the assumption that they behave like integers outside array addressing is wrong. – Thomas Jul 17 '13 at 00:34
  • 1
    @NeilKirk a floating point data type can be the same size (and therefore same bit representation) as an unsigned int, does that make it a special unsigned int – aaronman Jul 17 '13 at 00:38
  • @aaronman No I suppose not. – Neil Kirk Jul 17 '13 at 00:45
  • http://stackoverflow.com/questions/988158/take-the-address-of-a-one-past-the-end-array-element-via-subscript-legal-by-the relevant in that it discusses that you can only create a pointer to an element within bounds or **one past the end** and still be defined behavior. – Ryan Haining Jul 17 '13 at 01:02

4 Answers4

4

The math is valid; the resulting pointer isn't.

When you say ptr + i (where ptr is an int*), that evaluates to the address of an int that's i * sizeof(int) bytes past ptr. In this case, since your pointer points to a single int rather than an array of them, you have no idea (and C++ doesn't say) what's at p+10.

If, however, you had something like

int ii[20] = { 0 };
int *p = ii;
unsigned int y = 10;
cout << p + y;

Then you'd have a pointer you could actually use, because it still points to some location within the array it originally pointed into.

cHao
  • 84,970
  • 20
  • 145
  • 172
  • A link to a help page on pointer arithmetic would probably also benefit the OP. – Dennis Meng Jul 17 '13 at 00:32
  • 4
    You are, however, allowed to add 1 to the pointer. C++ is okay with you having a pointer that points to the memory position just past the end of something, provided you don't dereference it. – paddy Jul 17 '13 at 00:36
  • 2
    @DennisMeng and yet required for using standard algorithms on arrays since `end` iterators are one past the last element. – David Brown Jul 17 '13 at 00:45
  • @paddy What would you do with a pointer that points "one past the end" of a single object? Well you could invoke begin/end iterator-algorithms with this pointer as "end" but I consider this somehow pointless. Imho, a pointer one past a single object is just a pointer to unitialized memory and equally invalid as any other pointer to nirvana obtained by adding an arbitrary value to a valid pointer. – Pixelchemist Jul 17 '13 at 00:46
  • 1
    @DennisMeng: Not really. A common C++ idiom to pass a set of values involves passing the start point and the just-past-the-end point. If you passed `p` and `p + 1`, you could basically treat `x` as a sequence containing one integer, for the purposes of that call. Might be handy if you want to do something that expects a list of values, but you only have the one value and don't see the point of creating an array just for the sake of having an array. – cHao Jul 17 '13 at 00:46
  • I mean, I trust a standard thing like an iterator to not have that blow up in its face, but that doesn't make it not terrifying. – Dennis Meng Jul 17 '13 at 00:51
  • @cHao (and @DavidBrown): At a point where you have a single stack object you probably know that it's a single object and not an array so I personally don't see any reason for calling an algorithm operating on ranges with a single object. If you have a pointer where the number of objects may not be predetermined but is possibly equal to 1 this is meaningful but otherwise...? Can anyone of you give an example where treating a single object as an array in this way is desirable? – Pixelchemist Jul 17 '13 at 00:56
  • @DennisMeng: What'd really be terrifying is having the end point be the last element. That leads to all sorts of wackiness when you have, say, an empty range (zero elements); there's not really a good way to represent it. With one past the end, on the other hand, you don't have to care. You can say `for (current = start; current != end; ++current)` without fear, cause in an empty range, `start == end` and the loop's block never runs. – cHao Jul 17 '13 at 00:56
  • Okay, I'll concede that you have a good point there. I'm just personally not comfortable with any pointer where we know "if you dereference it will blow up in your face", but I can see its uses. – Dennis Meng Jul 17 '13 at 00:58
  • @Pixelchemist: Right off the top of my head? Say i want to use a function that works with ranges of chars. But i'm operating one char at a time, and don't feel like building an array for one char and saying `c[0]` or `*c` all the freaking time. :) – cHao Jul 17 '13 at 01:00
  • @DennisMeng If it makes you feel any better, it won't necessarily "blow up in your face". It's just undefined behaviour, which quite often seems to work just fine. Maybe that won't make you feel better. The fact is, when you are creating such pointers, you already know what they're for and why, so it's more like a handy tool than a terrifying concept. – paddy Jul 17 '13 at 01:25
  • @pixelchemist Sure, it's pointless in this case. I only said that it was allowed. It's more normal to take advantage of this when trawling through a string or some data buffer or, as people have pointed out, the standard containers. – paddy Jul 17 '13 at 01:28
  • @DennisMeng: I guess it can seem a bit scary at first...but it's pretty safe if you use it for its intended purpose (comparing with another pointer). And of course, since it's a common idiom in C++, it'd be a really good thing to get a feel for. :) – cHao Jul 17 '13 at 01:28
  • @paddy I'd rather not hope that "undefined behavior" doesn't blow up in my face. :P – Dennis Meng Jul 17 '13 at 01:34
  • @cHao Sure, of course. Mostly used to C here and haven't done much C++. – Dennis Meng Jul 17 '13 at 01:34
  • 1
    @DennisMeng The behaviour is undefined. If you expect it to have any characteristic at all (*eg* blowing up in your face) then you're fooling yourself. But that's all water under the bridge, because you're *not* going to dereference the pointer, are you... – paddy Jul 17 '13 at 01:36
  • @paddy I think we can safely say that we're now in agreement. :) – Dennis Meng Jul 17 '13 at 02:08
3

What you are doing in your code snippet is not converting unsigned int to pointer. Instead you are incrementing a pointer by an integer offset, which is a perfectly valid thing to do. When you access the index of an array, you basically take the pointer to the first element and increase it by the integer index value. The result of this operation is another pointer.

If p is a pointer/array, the following two lines are equivalent and valid (supposing the pointed-to-array is large enough)

p[5] = 1;
*(p + 5) = 1;

To convert unsigned int to pointer, you must use a cast

unsigned int i = 5;
char *p = reinterpret_cast<char *>(i);

However this is dangerous. How do you know 5 is a valid address?

A pointer is represented in memory as an unsigned integer type, the address. You CAN store a pointer in an integer. However you must be careful that the integer data type is large enough to hold all the bits in a pointer. If unsigned int is 32-bits and pointers are 64-bits, some of the address information will be lost.

C++11 introduces a new type uintptr_t which is guaranteed to be big enough to hold a pointer. Thus it is safe to cast a pointer to uintptr_t and back again.

It is very rare (should be never in run-of-the-mill programming) that you need to store pointers in integers.

However, modifying pointers by integer offsets is totally valid and common.

Ryan Haining
  • 35,360
  • 15
  • 114
  • 174
Neil Kirk
  • 21,327
  • 9
  • 53
  • 91
0

A variable of type int is a variable capable of containing an integer value. A variable of type int* is a pointer to a variable copable of containing an integer value.

Every pointer type has the same size and contains the same stuff: A memory address, which the size is 4 bytes for 32-bit arquitectures and 8 bytes for 64-bit arquitectures. What distinguish them is the type of the variable they are poiting to.

Pointers are useful to address buffers and structures allocated dynamically at run time or any sort of variable that is to be used but is stored somewhere else and you have to tell where.

Arithmetic operations with pointers are possible, but they won't do what you think. For instance, summing + 1 to a pointer of type int will increase its value by sizeof(int), not by literally 1, because its a pointer, and the logic here is that you want the next object of this array.

For instance:

int a[] = { 10, 20, 30, 40 };
int *b = a;
printf("%d\n", *b);
b = b + 1;
printf("%d\n", *b);

It will output:

10
20

Because b is pointing to the integer value 10, and when you sum 1 to it, or any variable containing an integer, its then poiting to the next value, 20.

If you want to perform operations with the variable stored at b, you can use:

*b = *b + 3;

Now b is the same pointer, the address has not changed. But the array 10, 20, 30, 40 now contains the values 13, 20, 30, 40, because you increased the element b was poiting to by 3.

Havenard
  • 27,022
  • 5
  • 36
  • 62
0

Is this a valid thing to do in c++, and if not why?

Yes. cout << p+y; is valid as you can see trying to compile it. Actually p+y is so valid that *(p+y) can be translated to p[y] which is used in C-style arrays (not that I'm suggesting its use in C++).

Valid doesn't mean it actually make sense or that the resulting pointer is valid. Since p points to an int the resulting pointer will be an offset of sizeof(int) * 10 from the location of x. And you are not certain about what's in there.

Shoe
  • 74,840
  • 36
  • 166
  • 272
  • not always true (about the location of the pointer). If the pointer does not refer to an element in bounds, or one past the end of an array, it is undefined behavior – Ryan Haining Jul 17 '13 at 01:01