Pointer arithmetic question

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Kenneth Brody

    #1

    Pointer arithmetic question

    Given the following:

    char *ptr1, *ptr2;
    size_t n;

    ptr2 = ptr1 + n;

    Assuming ptr1 is a valid pointer, is the following guaranteed to be true?

    (ptr2 - ptr1) == n

    What if n is greater than the size of the buffer to which ptr1 points?

    For example:

    char buf[10];
    char *pt = buf + 100;
    size_t n = (pt - buf);

    Is n guaranteed to be 100? Or, does the simple act of calculating an
    address off the end of the buffer (beyond the address that immediately
    follows the buffer) invoke UB?

    --
    +-------------------------+--------------------+-----------------------------+
    | Kenneth J. Brody | www.hvcomputer.com | |
    | kenbrody/at\spamcop.net | www.fptech.com | #include <std_disclaimer .h> |
    +-------------------------+--------------------+-----------------------------+
    Don't e-mail me at: <mailto:ThisIsA SpamTrap@gmail. com>


  • Vladimir S. Oka

    #2
    Re: Pointer arithmetic question

    Kenneth Brody wrote:[color=blue]
    > Given the following:
    >
    > char *ptr1, *ptr2;
    > size_t n;
    >
    > ptr2 = ptr1 + n;[/color]

    Undefined behaviour if n > 1. You must not dereference ptr2 if n
    == 1, but no overflow is generated. OK if n == 0.
    [color=blue]
    >
    > Assuming ptr1 is a valid pointer, is the following guaranteed to be true?
    >
    > (ptr2 - ptr1) == n
    >
    > What if n is greater than the size of the buffer to which ptr1 points?
    >
    > For example:
    >
    > char buf[10];
    > char *pt = buf + 100;[/color]

    Undefined behaviour (same C&V as above).
    You can only go one past the end of the array, and then
    you must not try to dereference the resultant pointer.
    [color=blue]
    > size_t n = (pt - buf);[/color]

    Correct type for n is diffptr_t from stddef.h
    [color=blue]
    >
    > Is n guaranteed to be 100? Or, does the simple act of calculating an
    > address off the end of the buffer (beyond the address that immediately
    > follows the buffer) invoke UB?
    >[/color]

    Yes it does.

    Cheers

    Vladimir

    PS
    C&V: 6.5.6.x, esp. 6.5.6.7-11.


    --
    My e-mail address is real, and I read it.

    Comment

    • Vladimir S. Oka

      #3
      Re: Pointer arithmetic question

      Vladimir S. Oka wrote:[color=blue]
      > Kenneth Brody wrote:[color=green]
      >> size_t n = (pt - buf);[/color]
      >
      > Correct type for n is diffptr_t from stddef.h
      >[/color]

      Would've easily won fastest-fingers-first... :-(

      It's ptrdiff_t from <stddef.h>, of course.

      Sorry

      Vladimir



      --
      My e-mail address is real, and I read it.

      Comment

      • mdler

        #4
        Re: Pointer arithmetic question

        Hello

        Adding pointers is not just 1+1 = 2 but the type of the pointer is
        importand.

        example

        double *a, b[100];
        a= b;
        printf("b-a=%d",a-(a+1));

        give 4 because the sizeod double is 4 byte

        subtract is straight forward
        plus is size of pointer type

        so you can do also

        double a[100];

        now is (&a[10] == a+10) gives TRUE
        wich type a is is not importand.

        Greetings

        Comment

        • Thomas Maier-Komor

          #5
          Re: Pointer arithmetic question

          Vladimir S. Oka wrote:[color=blue]
          > Kenneth Brody wrote:[color=green]
          >> Given the following:
          >>
          >> char *ptr1, *ptr2;
          >> size_t n;
          >>
          >> ptr2 = ptr1 + n;[/color]
          >
          > Undefined behaviour if n > 1. You must not dereference ptr2 if n == 1,
          > but no overflow is generated. OK if n == 0.
          >[/color]

          IMHO, this is not quite correct.

          It depends where ptr1 is pointing to. If ptr1 is pointing to a single
          char object, then n must not be anything else than 0 or 1.

          If ptr1 is pointing somewhere into an array of char, then n is allowed
          to be something else than 1 or 0. You must only make sure that the
          resulting pointer points to a valid place in the array or one past the
          end. Any other location will trigger UB.


          The relevant section is 6.5.6 paragraphs 7 and 8:
          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.

          When an expression that has integer type is added to or subtracted from
          a pointer, the
          result has the type of the pointer operand. If the pointer operand
          points to an element of
          an array object, and the array is large enough, the result points to an
          element offset from
          the original element such that the difference of the subscripts of the
          resulting and original
          array elements equals the integer expression. In other words, if the
          expression P points to
          the i-th element of an array object, the expressions (P)+N
          (equivalently, N+(P)) and
          (P)-N (where N has the value n) point to, respectively, the i+n-th and
          i−n-th elements of
          the array object, provided they exist. Moreover, if the expression P
          points to the last
          element of an array object, the expression (P)+1 points one past the
          last element of the
          array object, and if the expression Q points one past the last element
          of an array object,
          the expression (Q)-1 points to the last element of the array object. If
          both the pointer
          operand and the result point to elements of the same array object, or
          one past the last
          element of the array object, the evaluation shall not produce an
          overflow; otherwise, the
          behavior is undefined. If the result points one past the last element of
          the array object, it
          shall not be used as the operand of a unary * operator that is evaluated.

          Tom

          Comment

          • Dag-Erling Smørgrav

            #6
            Re: Pointer arithmetic question

            "mdler" <olaf.giezenaar @gmail.com> writes:[color=blue]
            > Adding pointers is not just 1+1 = 2 but the type of the pointer is
            > importand.
            >
            > example
            >
            > double *a, b[100];
            > a= b;
            > printf("b-a=%d",a-(a+1));
            >
            > give 4 because the sizeod double is 4 byte[/color]

            No. It prints -1.

            I assume that what you actually meant to write was something like

            printf("%d\n", &b[1] - &b[0]);

            which prints 1 regardless of the value of sizeof(b[0]).

            I suggest you read §6.5.6 carefully. To summarize, subtracting one
            pointer from another is only permitted when they both point to
            elements of the same array object, or one past the last element, and
            the result is the difference between the subscripts of the elements
            the pointers point to, so in effect:

            &a[i] - &a[j] == i - j

            DES
            --
            Dag-Erling Smørgrav - des@des.no

            Comment

            • Vladimir S. Oka

              #7
              Re: Pointer arithmetic question

              Thomas Maier-Komor wrote:[color=blue]
              > Vladimir S. Oka wrote:[color=green]
              >> Kenneth Brody wrote:[color=darkred]
              >>> Given the following:
              >>>
              >>> char *ptr1, *ptr2;
              >>> size_t n;
              >>>
              >>> ptr2 = ptr1 + n;[/color]
              >> Undefined behaviour if n > 1. You must not dereference ptr2 if n == 1,
              >> but no overflow is generated. OK if n == 0.
              >>[/color]
              >
              > IMHO, this is not quite correct.
              >
              > It depends where ptr1 is pointing to. If ptr1 is pointing to a single
              > char object, then n must not be anything else than 0 or 1.
              >
              > If ptr1 is pointing somewhere into an array of char, then n is allowed
              > to be something else than 1 or 0. You must only make sure that the
              > resulting pointer points to a valid place in the array or one past the
              > end. Any other location will trigger UB.
              >[/color]

              What you're saying is entirely correct (I point to same C&V).

              However, given what Kenneth posted, ptr1 and ptr2 point to a
              char object, not an array. They may be made to point to an array
              of char, but there's no telling whether they are in this case.

              Cheers

              Vladimir

              --
              My e-mail address is real, and I read it.

              Comment

              • Richard Tobin

                #8
                Re: Pointer arithmetic question

                In article <43D0F551.C7C6F 36@spamcop.net> ,
                Kenneth Brody <kenbrody@spamc op.net> wrote:
                [color=blue]
                >Given the following:
                >
                > char *ptr1, *ptr2;
                > size_t n;
                >
                > ptr2 = ptr1 + n;[/color]

                Stop right there! This is only allowed if it doesn't point beyond the
                end of the object that ptr1 points into.
                [color=blue]
                >Assuming ptr1 is a valid pointer, is the following guaranteed to be true?
                >
                > (ptr2 - ptr1) == n[/color]

                If the above condition holds, yes.
                [color=blue]
                >What if n is greater than the size of the buffer to which ptr1 points?[/color]

                No, and you've already gone wrong when you do the addition.
                [color=blue]
                >Or, does the simple act of calculating an
                >address off the end of the buffer (beyond the address that immediately
                >follows the buffer) invoke UB?[/color]

                Yes, exactly.

                Of course, it works perfectly well with natural C implementations on
                linear address-space machines.

                -- Richard

                Comment

                • Michael Mair

                  #9
                  Re: Pointer arithmetic question

                  Richard Tobin wrote:[color=blue]
                  > In article <43D0F551.C7C6F 36@spamcop.net> ,
                  > Kenneth Brody <kenbrody@spamc op.net> wrote:
                  >[color=green]
                  >>Given the following:
                  >>
                  >> char *ptr1, *ptr2;
                  >> size_t n;
                  >>
                  >> ptr2 = ptr1 + n;[/color]
                  >
                  >
                  > Stop right there! This is only allowed if it doesn't point beyond the
                  > end of the object that ptr1 points into.[/color]

                  One past the end is allowed, too.
                  Think of, e.g.
                  while (*(ptr1++) != '\0')

                  <snip>

                  Cheers
                  Michael
                  --
                  E-Mail: Mine is an /at/ gmx /dot/ de address.

                  Comment

                  • Richard Tobin

                    #10
                    Re: Pointer arithmetic question

                    In article <43cjt7F1mirkcU 2@individual.ne t>,
                    Michael Mair <Michael.Mair@i nvalid.invalid> wrote:
                    [color=blue][color=green]
                    >> Stop right there! This is only allowed if it doesn't point beyond the
                    >> end of the object that ptr1 points into.[/color][/color]
                    [color=blue]
                    >One past the end is allowed, too.
                    >Think of, e.g.
                    > while (*(ptr1++) != '\0')[/color]

                    I was considering that as pointing to the end, but thanks for
                    clarifying.

                    -- Richard

                    Comment

                    • Kenneth Brody

                      #11
                      Re: Pointer arithmetic question

                      Richard Tobin wrote:[color=blue]
                      >
                      > In article <43D0F551.C7C6F 36@spamcop.net> ,
                      > Kenneth Brody <kenbrody@spamc op.net> wrote:
                      >[color=green]
                      > >Given the following:
                      > >
                      > > char *ptr1, *ptr2;
                      > > size_t n;
                      > >
                      > > ptr2 = ptr1 + n;[/color]
                      >
                      > Stop right there! This is only allowed if it doesn't point beyond the
                      > end of the object that ptr1 points into.[/color]

                      Yes, I realize that. I was wondering if the mere calculation would
                      introduce UB, since I will never actually dereference the bad pointer.
                      Given the replies I've seen, the answer appears to be "yes, it does".
                      [color=blue][color=green]
                      > >Assuming ptr1 is a valid pointer, is the following guaranteed to be true?
                      > >
                      > > (ptr2 - ptr1) == n[/color]
                      >
                      > If the above condition holds, yes.
                      >[color=green]
                      > >What if n is greater than the size of the buffer to which ptr1 points?[/color]
                      >
                      > No, and you've already gone wrong when you do the addition.
                      >[color=green]
                      > >Or, does the simple act of calculating an
                      > >address off the end of the buffer (beyond the address that immediately
                      > >follows the buffer) invoke UB?[/color]
                      >
                      > Yes, exactly.
                      >
                      > Of course, it works perfectly well with natural C implementations on
                      > linear address-space machines.[/color]

                      Unfortunately, we all know that "works on system X does not mean that
                      it's valid code".

                      I was hoping to be able to take some existing code and enhance the
                      functionality (basically, building an array of struct which include
                      pointers into a buffer, where the buffer size used to be a known
                      quantity before the calculations, to one where the size wouldn't be
                      known until after building the array) without having to change the
                      basic interface. Looks like I'll have to take a different approach.
                      (And I'm not going to resort to storing (int)offset in a (char *)ptr,
                      which also "works" on these systems.)

                      Thanks to all those who responded.

                      --
                      +-------------------------+--------------------+-----------------------------+
                      | Kenneth J. Brody | www.hvcomputer.com | |
                      | kenbrody/at\spamcop.net | www.fptech.com | #include <std_disclaimer .h> |
                      +-------------------------+--------------------+-----------------------------+
                      Don't e-mail me at: <mailto:ThisIsA SpamTrap@gmail. com>


                      Comment

                      • Keith Thompson

                        #12
                        Re: Pointer arithmetic question

                        "Vladimir S. Oka" <novine@btinter net.com> writes:[color=blue]
                        > Thomas Maier-Komor wrote:[color=green]
                        >> Vladimir S. Oka wrote:[color=darkred]
                        >>> Kenneth Brody wrote:
                        >>>> Given the following:
                        >>>>
                        >>>> char *ptr1, *ptr2;
                        >>>> size_t n;
                        >>>>
                        >>>> ptr2 = ptr1 + n;
                        >>> Undefined behaviour if n > 1. You must not dereference ptr2 if n == 1,
                        >>> but no overflow is generated. OK if n == 0.
                        >>>[/color]
                        >> IMHO, this is not quite correct.
                        >> It depends where ptr1 is pointing to. If ptr1 is pointing to a single
                        >> char object, then n must not be anything else than 0 or 1.
                        >> If ptr1 is pointing somewhere into an array of char, then n is
                        >> allowed
                        >> to be something else than 1 or 0. You must only make sure that the
                        >> resulting pointer points to a valid place in the array or one past the
                        >> end. Any other location will trigger UB.[/color]
                        >
                        > What you're saying is entirely correct (I point to same C&V).
                        >
                        > However, given what Kenneth posted, ptr1 and ptr2 point to a char
                        > object, not an array. They may be made to point to an array of char,
                        > but there's no telling whether they are in this case.[/color]

                        Given what Kenneth posted, we have no idea what ptr1 and ptr2 point
                        to. If we take the code snippet literally, they're both
                        uninitialized, and any attempt to refer to the value of either invokes
                        undefined behavior, but we can reasonably assume that they're
                        initialized to *something*. In answering his question, we should take
                        all possibilities into account, particularly since char* pointers are
                        most commonly used to point to arrays rather than single char objects.

                        --
                        Keith Thompson (The_Other_Keit h) kst-u@mib.org <http://www.ghoti.net/~kst>
                        San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
                        We must do something. This is something. Therefore, we must do this.

                        Comment

                        • Thomas Maier-Komor

                          #13
                          Re: Pointer arithmetic question

                          Vladimir S. Oka wrote:[color=blue]
                          > Thomas Maier-Komor wrote:[color=green]
                          >> Vladimir S. Oka wrote:[color=darkred]
                          >>> Kenneth Brody wrote:
                          >>>> Given the following:
                          >>>>
                          >>>> char *ptr1, *ptr2;
                          >>>> size_t n;
                          >>>>
                          >>>> ptr2 = ptr1 + n;
                          >>> Undefined behaviour if n > 1. You must not dereference ptr2 if n == 1,
                          >>> but no overflow is generated. OK if n == 0.
                          >>>[/color]
                          >>
                          >> IMHO, this is not quite correct.
                          >>
                          >> It depends where ptr1 is pointing to. If ptr1 is pointing to a single
                          >> char object, then n must not be anything else than 0 or 1.
                          >>
                          >> If ptr1 is pointing somewhere into an array of char, then n is allowed
                          >> to be something else than 1 or 0. You must only make sure that the
                          >> resulting pointer points to a valid place in the array or one past the
                          >> end. Any other location will trigger UB.
                          >>[/color]
                          >
                          > What you're saying is entirely correct (I point to same C&V).
                          >
                          > However, given what Kenneth posted, ptr1 and ptr2 point to a char
                          > object, not an array. They may be made to point to an array of char, but
                          > there's no telling whether they are in this case.
                          >
                          > Cheers
                          >
                          > Vladimir
                          >[/color]

                          OK - I agree. But if you don't know where ptr1 is pointing, you cannot
                          assume safely that it is a char object. Beside an object in a char
                          array, it could also be a null pointer. However, in the case of ptr1
                          being null, n must be 0. For any other value of n you will get UB.

                          Cheers,
                          Tom

                          Comment

                          • Keith Thompson

                            #14
                            Re: Pointer arithmetic question

                            Thomas Maier-Komor <maierkom@lpr .e-technik.tu-muenchen.de> writes:
                            [...][color=blue]
                            > OK - I agree. But if you don't know where ptr1 is pointing, you cannot
                            > assume safely that it is a char object. Beside an object in a char
                            > array, it could also be a null pointer. However, in the case of ptr1
                            > being null, n must be 0. For any other value of n you will get UB.[/color]

                            Actually, adding 0 to a null pointer invokes undefined behavior:

                            If both the pointer operand and the result point to elements of
                            the same array object, or one past the last element of the array
                            object, the evaluation shall not produce an overflow; otherwise,
                            the behavior is undefined.

                            It's likely to quietly yield a null pointer on most implementations ,
                            but the standard doesn't require it.

                            --
                            Keith Thompson (The_Other_Keit h) kst-u@mib.org <http://www.ghoti.net/~kst>
                            San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
                            We must do something. This is something. Therefore, we must do this.

                            Comment

                            • Kenneth Brody

                              #15
                              Re: Pointer arithmetic question

                              Keith Thompson wrote:[color=blue]
                              >
                              > "Vladimir S. Oka" <novine@btinter net.com> writes:[/color]
                              [...][color=blue][color=green]
                              > > However, given what Kenneth posted, ptr1 and ptr2 point to a char
                              > > object, not an array. They may be made to point to an array of char,
                              > > but there's no telling whether they are in this case.[/color]
                              >
                              > Given what Kenneth posted, we have no idea what ptr1 and ptr2 point
                              > to. If we take the code snippet literally, they're both
                              > uninitialized, and any attempt to refer to the value of either invokes
                              > undefined behavior, but we can reasonably assume that they're
                              > initialized to *something*. In answering his question, we should take
                              > all possibilities into account, particularly since char* pointers are
                              > most commonly used to point to arrays rather than single char objects.[/color]

                              Yes, the first part was just a snippet to explain the principle, with the
                              assumption that people would understand that ptr1 and n would contain
                              valid values. I also included a specific example:

                              char buf[10];
                              char *pt = buf + 100;
                              size_t n = (pt - buf);

                              --
                              +-------------------------+--------------------+-----------------------------+
                              | Kenneth J. Brody | www.hvcomputer.com | |
                              | kenbrody/at\spamcop.net | www.fptech.com | #include <std_disclaimer .h> |
                              +-------------------------+--------------------+-----------------------------+
                              Don't e-mail me at: <mailto:ThisIsA SpamTrap@gmail. com>

                              Comment

                              Working...