C pointer to last element of array

15,781

Solution 1

I can suggest the following solution

#include <stdio.h>

int main( void )
{
    int a[4] = { 0, 1, 2, 3, };

    int *p = (int *)(&a + 1) - 1;

    printf("*p = %d\n", *p);

    return 0;
}

The program output is

*p = 3

Solution 2

You're probably thinking of something that involved &a + 1, which is a pointer to the memory just past the end of the struct.

However, (&a)[1][-1], or the identical expression but substituting pointer notation for array notation, *(&a + 1))[-1] or *(*(&a + 1) - 1), is technically undefined behaviour. But someone might have written this as a "clever trick" not realizing it was undefined.

((int *)(&a + 1))[-1] is well-defined and does the job, although arguably harder to read than just writing straightforward code.

Share:
15,781
Raul Grigorașcu
Author by

Raul Grigorașcu

Updated on June 04, 2022

Comments

  • Raul Grigorașcu
    Raul Grigorașcu almost 2 years

    Lets say we have an array

    int a[4];

    there was a neat trick using pointer arithmetics to find the last element. As far as i can recall it was using the address of 'a' and incrementing it so that it will go point immediately after the array and then going one position back. The thought behind the incrementing was that that there was an implicit sizeof being done. There was nowhere any explicit sizeof.

    Anyone have any idea how it was done?

    Thanks a bunch!

    • Admin
      Admin almost 7 years
      maybe something like *(&a + 1) - 1 (not checked/tested and I doubt this is well-defined)
    • Spikatrix
      Spikatrix almost 7 years
      See my question: Is *((*(&array + 1)) - 1) safe to use to get the last element of an automatic array?. In short, *(&array + 1) invokes UB.
    • too honest for this site
      too honest for this site almost 7 years
      Not clear what you mean. There is no "trick" involved. ("Tricks" are most times a bad idea anyway.)
    • Admin
      Admin almost 7 years
      @kay I doubt it because although it's ok to have a pointer pointing one after the end of an object, for my "trick" here, I need to dereference this pointer ....
    • M.M
      M.M almost 7 years
      ((int *)(&a + 1))[-1] would be well-defined though (avoids the problem of dereferencing the past-the-end pointer)
    • Eugene Sh.
      Eugene Sh. almost 7 years
      @M.M is (int *)(&a + 1) cast valid? The pointer types are incompatible, I think...
    • Ctx
      Ctx almost 7 years
      Is there a good reason to avoid sizeof()? Or is it a pure academical question?
    • Ian Abbott
      Ian Abbott almost 7 years
      Is a[sizeof a / sizeof *a - 1] not concise enough?
    • M.M
      M.M almost 7 years
      @EugeneSh. the whole purpose of a pointer cast is to cast between incompatible types
    • Eugene Sh.
      Eugene Sh. almost 7 years
      @M.M But then there is a pointer arithmetic performed on it. Technically it is within the boundaries of a, but a has a different type of the one pointed by the pointer the arithmetic is performed on. So it looks a bit suspicious to me.
    • chux - Reinstate Monica
      chux - Reinstate Monica almost 7 years
      @IanAbbott detail a[sizeof a / sizeof *a - 1] is the last element of the array. OP wants "pointer to last element of array". Presumable &a[sizeof a / sizeof *a - 1] would work.
    • Raul Grigorașcu
      Raul Grigorașcu almost 7 years
      Wow, thanks guys! I knew it was something remarkably simple. Thanks alot!
    • JeremyP
      JeremyP almost 7 years
      @chux a + sizeof a / sizeof *a - 1 is a pointer
  • chux - Reinstate Monica
    chux - Reinstate Monica almost 7 years
    Note: the int* cast appears ok per "A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined." C11 §6.3.2.3 7.