问题
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!
回答1:
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.
回答2:
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.
- Some iterator types permit such an operation, but this is not one of them (even though pointers are a kind of iterator).
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 ofx
and an object of typeT
that is not an array element is considered to belong to an array with one element of typeT
. [..]
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 expressionP
of pointer type, the result has the type ofP
.
- If
P
evaluates to a null pointer value andJ
evaluates to0
, the result is a null pointer value.- Otherwise, if
P
points to an array element i of an array objectx
with n elements ([dcl.array]),80 the expressionsP + J
andJ + P
(whereJ
has the valuej
) point to the (possibly-hypothetical) array element i+j ofx
if 0≤i+j≤n and the expressionP - J
points to the (possibly-hypothetical) array element i−j ofx
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.
来源:https://stackoverflow.com/questions/65172368/is-incrementing-decrementing-or-adding-an-integer-value-to-a-pointer-that-is-not