Velocity Reviews > Pointer arithmetic question

# Pointer arithmetic question

Kenneth Brody
Guest
Posts: n/a

 01-20-2006
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: <(E-Mail Removed)>

Guest
Posts: n/a

 01-20-2006
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.

>
> 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;

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.

> size_t n = (pt - buf);

Correct type for n is diffptr_t from stddef.h

>
> 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?
>

Yes it does.

Cheers

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

--

Guest
Posts: n/a

 01-20-2006
> Kenneth Brody wrote:
>> size_t n = (pt - buf);

>
> Correct type for n is diffptr_t from stddef.h
>

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

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

Sorry

--

mdler
Guest
Posts: n/a

 01-20-2006
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

Thomas Maier-Komor
Guest
Posts: n/a

 01-20-2006
> 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.
>

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

=?iso-8859-1?q?Dag-Erling_Sm=F8rgrav?=
Guest
Posts: n/a

 01-20-2006
"mdler" <(E-Mail Removed)> writes:
> 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

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 - http://www.velocityreviews.com/forums/(E-Mail Removed)

Guest
Posts: n/a

 01-20-2006
Thomas Maier-Komor wrote:
>> 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.
>>

>
> 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.
>

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

--

Richard Tobin
Guest
Posts: n/a

 01-20-2006
In article <(E-Mail Removed)>,
Kenneth Brody <(E-Mail Removed)> wrote:

>Given the following:
>
> char *ptr1, *ptr2;
> size_t n;
>
> ptr2 = ptr1 + n;

Stop right there! This is only allowed if it doesn't point beyond the
end of the object that ptr1 points into.

>Assuming ptr1 is a valid pointer, is the following guaranteed to be true?
>
> (ptr2 - ptr1) == n

If the above condition holds, yes.

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

>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?

Yes, exactly.

Of course, it works perfectly well with natural C implementations on

-- Richard

Michael Mair
Guest
Posts: n/a

 01-20-2006
Richard Tobin wrote:
> In article <(E-Mail Removed)>,
> Kenneth Brody <(E-Mail Removed)> wrote:
>
>>Given the following:
>>
>> char *ptr1, *ptr2;
>> size_t n;
>>
>> ptr2 = ptr1 + n;

>
>
> Stop right there! This is only allowed if it doesn't point beyond the
> end of the object that ptr1 points into.

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.

Richard Tobin
Guest
Posts: n/a

 01-20-2006
In article <(E-Mail Removed)>,
Michael Mair <(E-Mail Removed)> wrote:

>> Stop right there! This is only allowed if it doesn't point beyond the
>> end of the object that ptr1 points into.

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

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

-- Richard