4

Consider

int main()
{
    char* p = malloc(5);
    printf("%td", &p[5] - &p[0]); /*one past the end is allowed*/
    free(p);
    printf("%td", &p[5] - &p[0]); /*I no longer own p*/
}

Is the behaviour of this code defined? Are you allowed to perform pointer arithmetic on an array that you no longer own?

  • 5
    You can do the arithmetic. You may not access the array anymore. – Paul Ogilvie Jul 17 '17 at 12:34
  • 2
    where did you get that `p[5]` was allowed (one past the end??) – Jean-François Fabre Jul 17 '17 at 12:35
  • 8
    Possible duplicate of [Arithmetic on freed pointer](https://stackoverflow.com/questions/11733814/arithmetic-on-freed-pointer) – Andre Kampling Jul 17 '17 at 12:36
  • `&p[5]` must not attempt to *dereference* `p`. In order words `&p[5]` must compile to `p + 5` with no dereference on `p`. – Fitzwilliam Bennet-Darcy Jul 17 '17 at 12:36
  • check this [post](https://stackoverflow.com/questions/7147081/c-design-your-own-free-function) – Charles Jul 17 '17 at 13:07
  • 1
    @PaulOgilvie-- even pointer arithmetic beyond `p+1` is undefined behavior after `p` has been `free`d. – ad absurdum Jul 17 '17 at 13:20
  • 2
    @FitzwilliamBennet-Darcy: That's true. However, even evaluating the pointer *itself* (say, pointer arithmetic) is undefined behavior when it's out of range of an object (be it a stack- or heap-allocated one). In other words, a pointer, even if not dereferenced, ***must*** point to a location in an object, or the location immediately following one. Thus, your code is undefined behavior. Many (most?) compilers do allow it in practice, but I wouldn't count on it. – Tim Čas Jul 17 '17 at 13:22
  • @David Bowling, may I assume, as an example, that a compiler seeing that `p` has been freed, may use the storage location of `p` for some other purpose? – Paul Ogilvie Jul 17 '17 at 14:04
  • @PaulOgilvie-- yes, I think so. I think that my earlier comment was wrong, in that even attempting to form the address `p+1` incurs UB, since `p` no longer points to an array object, not even to an array object of 1 element. – ad absurdum Jul 17 '17 at 15:48

2 Answers2

4

Yes, you're usually allowed to do that on many compilers in many environments.

You have to keep in mind, however, that the ISO C standard doesn't have any requirement for your language when you do it, however: it doesn't define the behavior any use of a pointer whose value is "indeterminate". According to ISO C, the value of p after free(p) has essentially the same status as if it were uninitialized.

Kaz
  • 55,781
  • 9
  • 100
  • 149
3

Are you looking for the language lawyer answer, or the practical answer?

The language lawyer answer is, no, it's undefined.

The practical answer is: yes, it'll probably work, but it's a bad idea. I would always compute the difference (and store it in a variable if necessary) before freeing the pointer.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
  • "*... it's undefined..*" I am with, but seem to be unable to find the related paragraph in the C11-Standard. 6.5.6/8 I feel is somewhat ambiguous. – alk Jul 18 '17 at 04:12
  • @alk-- what about §6.5.6 9: "When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object...." After `free(p);`, `p` does not point to an array object, I think. – ad absurdum Jul 19 '17 at 14:02