5

In the textbook "Modern C" by Jens Gustedt, I read for pointers that "A pointer must point to a valid object or one position beyond a valid object or be null.". Why is pointing to one position beyond a valid object acceptable? E.g.:

int array[5] = {0};
int* p = array;
p = array + 5 // points to a valid location
p = array + 6 // points to an invalid location
Boann
  • 48,794
  • 16
  • 117
  • 146
Alex
  • 358
  • 1
  • 11
  • 1
    Please cite the textbook. I'd like to read it. – Jeff Holt Jul 23 '20 at 12:54
  • 2
    `p = array + 5 // points to a valid location` -- No, it does not! – Fred Larson Jul 23 '20 at 12:54
  • 3
    When iterating an array and post-incrementing a pointer, it allows the last element to be treated the same as the other elements without making a special case of it. Pointing to one beyond, does not mean that it can be dereferenced. – Weather Vane Jul 23 '20 at 12:59
  • @JeffHolt The textbook is called "Modern C" written by Jens Gustedt. – Alex Jul 23 '20 at 13:03
  • @FredLarson: Re “points to a valid location”: There is slack in the terminology here. The C standard does not define this phrase. One could use “points to a valid location” to mean the pointer value is well defined but not that one can access an object at that location. – Eric Postpischil Jul 23 '20 at 13:05
  • The quote is wrong; if it weren't, the code `int main () { int* p; }` were invalid, because an uninitialized pointer might point anywhere random. If you dereference a pointer, it has to point to a valid object. If you want to compare or subtract pointers, they have to point into or one-past the same array, or be null. – Erlkoenig Jul 23 '20 at 13:07
  • @EricPostpischil: Does the standard *use* that phrase for this situation? "points to a valid location" to me means you could safely dereference it, which is not the case here. – Fred Larson Jul 23 '20 at 13:08
  • @Alex [@JensGustedt](https://stackoverflow.com/users/366377/jens-gustedt) (the author) is an active member here. Maybe he will answer what he meant himself. :-) – RobertS supports Monica Cellio Jul 23 '20 at 13:14
  • @EricPostpischil There are [argumentation](https://stackoverflow.com/questions/62932383/accessing-struct-elements-using-single-pointer/62933027#comment111291779_62932383) that even the incremented pointer value isn't well-defined because of §6.5.6/8. How about that? – RobertS supports Monica Cellio Jul 23 '20 at 13:35
  • 1
    @RobertSsupportsMonicaCellio: The comment you point to does not say that. That comment is in the context where `p_a` points to a structure member, not to an array, and so `p_a+4` is not defined. That has nothing to do with pointer arithmetic within an array and the position one beyond its last element. – Eric Postpischil Jul 23 '20 at 13:37
  • @EricPostpischil I thought that too but §6.5.6/7 says "*For the purposes of these operators, a pointer to an object that is not an element of an array behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type.*" which made the premise that pointer to scalar objects apply to §6.5.6/8, too. – RobertS supports Monica Cellio Jul 23 '20 at 13:53
  • 1
    Yes, @RobertSsupportsMonicaCellio. So for any lvalue `x`, it is allowed to evaluate `&x + 1`, to store the result, and to work with it in a variety of ways. That counts as a pointer to one element past the end of an array. But for many -- ***although not all*** -- lvalues, computing `&x + 2`, `&x + 3`, *etc*. has undefined behavior, and you and M.M. were discussing one of those cases. – John Bollinger Jul 23 '20 at 13:58

2 Answers2

12

Supporting “one beyond the last” makes working with arrays simpler. For example, if a function is called with a pointer Start to some element, it might want to prepare an end pointer End and use a loop such as:

for (ElementType *p = Start; p < End; ++p)

To do this, End must be a valid pointer.

We might consider instead setting End to be the last element to be processed, rather than one beyond it, and using:

for (ElementType *p = Start; p <= End; ++p)

However, note that, after the final element is processed, p will be incremented to beyond End. Then, in order for p <= End to be a valid expression, p must be a valid pointer. So, we need to be able to do address arithmetic up to one beyond the last element of an array.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • thanks for the answer, assigning to the location "one position beyond a valid object" through a pointer is still considered invalid, right? – Alex Jul 23 '20 at 13:02
  • @Alex: Yes, the pointer is valid (its value may be used in pointer comparisons and arithmetic), but attempting to access (read or write) what the pointer points to is not defined by the C standard. – Eric Postpischil Jul 23 '20 at 13:03
3

Your code comments express a probable misunderstanding. With ...

int array[5] = {0};
int* p = array;
p = array + 5 // points to a valid location

... p does not point to a valid location. It is allowed and well defined to evaluate array + 5, and that produces a value that p can store, but undefined behavior results from any attempt to dereference that pointer value.

Such a value for p is sometimes useful as an exclusive upper bound on the addresses of elements of array, or for indexing array backwards (with strictly negative indexes), but you may not attempt to access a value through that value itself.

In contrast, in this case ...

p = array + 6 // points to an invalid location

... p does not point to anything, at least inasmuch as can be determined by analysis of the code. Attempting to evaluate the expression array + 6 produces undefined behavior, and in particular, the result is not well defined.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • Re “point to a valid location”: There is slack in the terminology here. The C standard does not define this phrase. One could use “point to a valid location” to mean the pointer value is well defined but not that one can access an object at that location. – Eric Postpischil Jul 23 '20 at 13:04
  • I am not inclined to argue that point, @EricPostpischil. My remarks about and using that phrase in this answer are directed toward interpreting the OP's use of it, and refuting what I take, in context, to be their most probable meaning. It is possible that they in fact mean something different, in which case I think the difference in meaning between them and me will be clear to them from context. – John Bollinger Jul 23 '20 at 13:46