11

I know that pointers (to array element) and iterators can be incremented/decremented to walk a sequence of elements and can jump back-and-for elements in the sequence.

But what will happen if I increment a pointer to a single object or add to it an integer value? is it undefined behavior or it is OK but we cannot access that memory?

int x = 551;
int* p = &x;
++p;
--p;
std::cout << *p << '\n';

Because I've already read that we should not increment/decrement a pointer that doesn't point to an element in a sequence or an array for example.

So can someone explain what will happen and whether my example is OK (de-referencing pointer p)? Thank you!

Itachi Uchiwa
  • 3,044
  • 12
  • 26
  • 1
    This is a very good question, because compiler writers are getting ever more aggressive at exploiting undefined behavior rules and making code have totally unpredictable consequences when you accidentally trip over a corner case. – Mark Ransom Dec 06 '20 at 20:33
  • That's not a great duplicate. It doesn't even touch on the subtraction case, which could reasonably have been (but actually isn't) handled differently. – Asteroids With Wings Dec 06 '20 at 21:13
  • @AsteroidsWithWings Yeah, that's reasonable. This is slightly more general than the other. I'll swing the target direction, thanks. – cigien Dec 06 '20 at 21:19

2 Answers2

2

when pointer arithmetic applies to a pointer that points to an object, the pointer is considered to point to an array of that object type with only one element, as said in the standard.

An object that is not an array element is considered to belong to a single-element array for this purpose

In you example, the pointer p as if it point to int arr[1] = {551} So, the corresponding operation is similar to apply to a pointer that point to the arr. That means, ++p will make p point to the element arr[1] (hypothetical), and --p will make p point to the first element arr[0] again. So, in the last, de-referenceing pointer p is OK and does not result in any UB.

-5

Summary

Your program is not well-defined, even before getting to the dereference.

  • You may increment p once, resulting in a one-past-the-end pointer.
  • However, you may not decrement a one-past-the-end pointer.

Standardese

The rules in the standard relating to this capability are given in terms of arrays, but a note reminds us that a single object is considered to be an element of a single-element array for these purposes, citing the following passage which describes the meaning of your pointer:

[basic.compound/3]: [..] A value of a pointer type that is a pointer to or past the end of an object represents the address of the first byte in memory ([intro.memory]) occupied by the object46 or the first byte in memory after the end of the storage occupied by the object, respectively. [..] For purposes of pointer arithmetic ([expr.add]) and comparison ([expr.rel], [expr.eq]), a pointer past the end of the last element of an array x of n elements is considered to be equivalent to a pointer to a hypothetical array element n of x and an object of type T that is not an array element is considered to belong to an array with one element of type T. [..]

So, yes, you can safely "get" the one-past-the-end pointer per these rules. Unfortunately, you can't do much with it afterwards, since the pointer addition and subtraction rules are defined thus:

[expr.add/4]: When an expression J that has integral type is added to or subtracted from an expression P of pointer type, the result has the type of P.

  • If P evaluates to a null pointer value and J evaluates to 0, the result is a null pointer value.
  • Otherwise, if P points to an array element i of an array object x with n elements ([dcl.array]),80 the expressions P + J and J + P (where J has the value j) point to the (possibly-hypothetical) array element i+j of x if 0≤i+j≤n and the expression P - J points to the (possibly-hypothetical) array element i−j of x if 0≤i−j≤n.
  • Otherwise, the behavior is undefined.

…and &x+1 is not an element of even the made-up array presented by the object x.

If it said "if P points to a (possibly-hypothetical) array element i of an array object x with n elements" then you'd be fine, because this would expand the behaviour given in the second bullet point to cover the one-past-the-end pointer (which is a "hypothetical array element of x" per the first quote). But it doesn't, so we fall through to the third bullet point, leaving your program with undefined behaviour.

Asteroids With Wings
  • 17,071
  • 2
  • 21
  • 35
  • Comments are not for extended discussion; this conversation has been [moved to chat](https://chat.stackoverflow.com/rooms/225647/discussion-on-answer-by-asteroids-with-wings-is-incrementing-decrementing-or-add). – Machavity Dec 07 '20 at 23:47