Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Neatest way to get the end pointer?

Reply
Thread Tools

Neatest way to get the end pointer?

 
 
vippstar@gmail.com
Guest
Posts: n/a
 
      02-06-2008
On Feb 6, 2:34 am, Peter Nilsson <(E-Mail Removed)> wrote:
> (E-Mail Removed) wrote:
> > Keith Thompson <(E-Mail Removed)> wrote:
> > > (E-Mail Removed) writes:
> > > > "Tomás Ó hÉilidhe" <(E-Mail Removed)> wrote:
> > > > > I commonly use pointers to iterate thru an array.
> > > > > For example:
> > > > > int my_array[X];
> > > [snip]
> > > > > 1) my_array is an int[X]
> > > > > 2) &my_array is an int(*)[X]
> > > > > 3) &my_array+1 is the address of the non-existant
> > > > > array located after the current one.

>
> > > > And you invoke undefined behavior.

>
> > > No, he doesn't. &my_array+1 is a valid address,

>
> Though it requires a conversion back to int * if used
> as a pointer 'index' compared against an int * iterator.
>
> > > just past the end of my_array. Computing this address
> > > is ok; attempting to dereference it would invoke UB.

>
> > I think that when the result of an expression is a non-
> > valid pointer, the behavior is undefined.

>
> True, but one byte past the end of an array _is_ a valid
> pointer.

Ah I see, thanks a lot.
> > Correct me if I am wrong,

>
> Keith already has.

Hehe, sorry mr Keith for doubting .

However, as you said mr Nilsson, he (the OP) is then dereferencing it,
and invoking undefined behavior.
Also, the whole topic is moot.
if sizeof foo / sizeof *foo gives you the elements of foo, then foo
must be an array.
If it's an array it must be defined as 'foo[X]' or similar.
If X is a constant, foo + X is the last pointer (that is not valid to
dereference), if X is an object, it is still foo + X, however foo is
then a variable length array.
Therefore, there is no need for foo + sizeof foo / sizeof *foo.
 
Reply With Quote
 
 
 
 
A. Sinan Unur
Guest
Posts: n/a
 
      02-06-2008
http://www.velocityreviews.com/forums/(E-Mail Removed) wrote in
news:(E-Mail Removed):

> On Feb 6, 2:08 am, Keith Thompson <(E-Mail Removed)> wrote:
>> (E-Mail Removed) writes:
>> > On Feb 6, 12:40 am, "Tomás Ó hÉilidhe" <(E-Mail Removed)> wrote:
>> >> I commonly use pointers to iterate thru an array. For example:

>>
>> >> int my_array[X];

>> [snip]
>> >> 1) my_array is an int[X]
>> >> 2) &my_array is an int(*)[X]
>> >> 3) &my_array+1 is the address of the non-existant array located
>> >> after the current one.
>> > And you invoke undefined behavior.

>>
>> [...]
>>
>> No, he doesn't. &my_array+1 is a valid address, just past the end of
>> my_array. Computing this address is ok; attempting to dereference it
>> would invoke UB.

> I think that when the result of an expression is a non-valid pointer,
> the behavior is undefined.
> Correct me if I am wrong, but I have also seen comments in GNU code
> like this:
> --
> /* ANSI C violation */
> char * s = p - 1;
> --
> Where p points to the start of a string passed. 's' is never
> dereferenced, only used for comparing purposes (while(p > s) or
> something similar)


That is different, though. Pointing one past the end of the array is
valid whereas pointing oen before the start of the array is not.

http://www.open-std.org/jtc1/sc22/wg...docs/n1124.pdf

§6.5.6, page 83

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.


Sinan


--
A. Sinan Unur <(E-Mail Removed)>
(remove .invalid and reverse each component for email address)
clpmisc guidelines: <URL:http://www.rehabitation.com/clpmisc.shtml>

 
Reply With Quote
 
 
 
 
Ben Bacarisse
Guest
Posts: n/a
 
      02-06-2008
(E-Mail Removed) writes:

> On Feb 6, 12:40 am, "Tomás Ó hÉilidhe" <(E-Mail Removed)> wrote:
>> I commonly use pointers to iterate thru an array. For example:
>>
>> int my_array[X];
>>
>> int *p = my_array;
>> int const *const pend = my_array + sizeof my_array/sizeof*my_array;

<snip>
>> It's a right pain in the ass to always have to write out the long-winded
>> intialiser for pend, so I'm considering switching to initialising pend
>> as follows:
>>
>> int const *const pend = *(&my_array+1);
>>
>> 1) my_array is an int[X]
>> 2) &my_array is an int(*)[X]
>> 3) &my_array+1 is the address of the non-existant array located after
>> the current one.


> And you invoke undefined behavior.


Presumably not from the pointer arithmetic alone? Is it the deference
that you think causes UB?

That is my worry. One can construct a pointer "one past the end" of
any object, but * can't be applied "if it is evaluated" (6.5.6 p. I
take that to refer to the rule that says that when & is applied to *,
neither are evaluated (6.5.3.2 p3).

I can't see anything wrong with:

int *pend = (void *)(&my_array + 1);

from a language point of view, but it is fragile in that it breaks
when the code moves to a function and my_array becomes a pointer.

Since "C has no array values" is one way of looking at the while
array/pointer relationship in C, one could argue that the * is not
evaluated in

int *pend = *(&my_array + 1);

Is the utility of this code sufficient to warrant a change to the
meaning of * (or definition of pointer arithmetic) to permit its use
when the "value" would be an array and would therefore be immediately
converted to a pointer?

--
Ben.
 
Reply With Quote
 
Richard Tobin
Guest
Posts: n/a
 
      02-06-2008
In article <foav6k$pfa$(E-Mail Removed)>,
Walter Roberson <(E-Mail Removed)-cnrc.gc.ca> wrote:

>> if (some_test_fails)
>> return (errno = ESOMETHING), (void *)NULL;


>No, if the return type of your function is a pointer then the
>return value will be converted to the appropriate type as if by
>assignment.


But the code is revolting anyway. I can see the temptation to
do something like

if(condition) a=1, b=2;

to avoid a block, but shoving an extra assignment into a return
statement is an unprovoked assault on readability.

-- Richard
--
:wq
 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      02-06-2008
(E-Mail Removed) writes:
> On Feb 6, 2:08 am, Keith Thompson <(E-Mail Removed)> wrote:
>> (E-Mail Removed) writes:
>> > On Feb 6, 12:40 am, "Tomás Ó hÉilidhe" <(E-Mail Removed)> wrote:
>> >> I commonly use pointers to iterate thru an array. For example:

>>
>> >> int my_array[X];

>> [snip]
>> >> 1) my_array is an int[X]
>> >> 2) &my_array is an int(*)[X]
>> >> 3) &my_array+1 is the address of the non-existant array located after
>> >> the current one.
>> > And you invoke undefined behavior.

>>
>> [...]
>>
>> No, he doesn't. &my_array+1 is a valid address, just past the end of
>> my_array. Computing this address is ok; attempting to dereference it
>> would invoke UB.

> I think that when the result of an expression is a non-valid pointer,
> the behavior is undefined.
> Correct me if I am wrong, but I have also seen comments in GNU code
> like this:
> --
> /* ANSI C violation */
> char * s = p - 1;
> --
> Where p points to the start of a string passed. 's' is never
> dereferenced, only used for comparing purposes (while(p > s) or
> something similar)


Computing a pointer before the beginning of an array invokes UB;
computing a pointer just past the end of an array does not.

This is mentioned in passing in the answer to question 6.17 in the
comp.lang.c FAQ, <http://www.c-faq.com/> (can anyone find a more
explicit reference?).

The standard's rather long-winded explanation of this is in C99
6.5.6p8 (quoting from n1256; there are no change bars on this
paragraph):

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

--
Keith Thompson (The_Other_Keith) <(E-Mail Removed)>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
Peter Nilsson
Guest
Posts: n/a
 
      02-06-2008
(E-Mail Removed) wrote:
> Peter Nilsson <(E-Mail Removed)> wrote:
> > ... one byte past the end of an array _is_ a valid
> > pointer.

>
> Hehe, sorry mr Keith for doubting .
>
> However, as you said mr Nilsson, he (the OP) is then
> dereferencing it, and invoking undefined behavior.


I never said the OP dereferenced it. The actual code had
been snipped by that point. Here it is...

int *p = my_array;
int const *const pend = my_array + sizeof my_array/
sizeof*my_array;
do *p++ = 42;
while (pend != p);

At no stage is pend dereferenced; and the loop exits on
p == pend, so the address is not dereferenced by p
either.

--
Peter
 
Reply With Quote
 
vippstar@gmail.com
Guest
Posts: n/a
 
      02-06-2008
On Feb 6, 4:01 am, Peter Nilsson <(E-Mail Removed)> wrote:
> (E-Mail Removed) wrote:
> > Peter Nilsson <(E-Mail Removed)> wrote:
> > > ... one byte past the end of an array _is_ a valid
> > > pointer.

>
> > Hehe, sorry mr Keith for doubting .

>
> > However, as you said mr Nilsson, he (the OP) is then
> > dereferencing it, and invoking undefined behavior.

>
> I never said the OP dereferenced it. The actual code had
> been snipped by that point. Here it is...
>
> int *p = my_array;
> int const *const pend = my_array + sizeof my_array/
> sizeof*my_array;
> do *p++ = 42;
> while (pend != p);
>
> At no stage is pend dereferenced; and the loop exits on
> p == pend, so the address is not dereferenced by p
> either.

Ah, I was a bit confused I guess.
However, OP _does_ dereference it. Not in that snipped, but in 4)
> 4) *(&my_array+ 1) decays to the address of the first element in the
> non-existant array after the current one, which is also the "pend"
> address for the array that actually exists.

 
Reply With Quote
 
vippstar@gmail.com
Guest
Posts: n/a
 
      02-06-2008
On Feb 6, 3:05 am, Keith Thompson <(E-Mail Removed)> wrote:
> (E-Mail Removed) writes:
> > On Feb 6, 2:08 am, Keith Thompson <(E-Mail Removed)> wrote:
> >> (E-Mail Removed) writes:
> >> > On Feb 6, 12:40 am, "Tomás Ó hÉilidhe" <(E-Mail Removed)> wrote:
> >> >> I commonly use pointers to iterate thru an array. For example:

>
> >> >> int my_array[X];
> >> [snip]
> >> >> 1) my_array is an int[X]
> >> >> 2) &my_array is an int(*)[X]
> >> >> 3) &my_array+1 is the address of the non-existant array located after
> >> >> the current one.
> >> > And you invoke undefined behavior.

>
> >> [...]

>
> >> No, he doesn't. &my_array+1 is a valid address, just past the end of
> >> my_array. Computing this address is ok; attempting to dereference it
> >> would invoke UB.

> > I think that when the result of an expression is a non-valid pointer,
> > the behavior is undefined.
> > Correct me if I am wrong, but I have also seen comments in GNU code
> > like this:
> > --
> > /* ANSI C violation */
> > char * s = p - 1;
> > --
> > Where p points to the start of a string passed. 's' is never
> > dereferenced, only used for comparing purposes (while(p > s) or
> > something similar)

>
> Computing a pointer before the beginning of an array invokes UB;
> computing a pointer just past the end of an array does not.
>
> This is mentioned in passing in the answer to question 6.17 in the
> comp.lang.c FAQ, <http://www.c-faq.com/> (can anyone find a more
> explicit reference?).
>
> The standard's rather long-winded explanation of this is in C99
> 6.5.6p8 (quoting from n1256; there are no change bars on this
> paragraph):
>
> 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 in-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.

I have thought about this, and clearly the standard talks about
arrays.
If we have foo[N], then foo + N is a valid pointer that cannot be
dereferenced.
However, in foo = &bar; foo+1 is *not* a valid pointer because &bar is
a pointer, not an array.
Therefore, in OPs example, the expression cannot be computed and does
invoke undefined behavior.
Here is an example of what i am trying to say
--
int * foo;
int bar;
int baz[N];
foo = baz + N; /* valid */
foo = &bar + 1; /* invalid */
foo = &bar; /* valid */
foo++; /* invalid */
--
 
Reply With Quote
 
Peter Nilsson
Guest
Posts: n/a
 
      02-06-2008
(E-Mail Removed) wrote:
> Peter Nilsson <(E-Mail Removed)> wrote:
> > ...
> > * int *p = my_array;
> > * int const *const pend = my_array + sizeof my_array/
> > * * * * * * * * * * * * * * * * * * *sizeof*my_array;
> > * do *p++ = 42;
> > * while (pend != p);

>
> > At no stage is pend dereferenced; and the loop exits on
> > p == pend, so the address is not dereferenced by p
> > either.

>
> Ah, I was a bit confused I guess.
> However, OP _does_ dereference it. Not in that snipped,
> but in 4)
>
> > 4) *(&my_array+ 1) decays to the address of the first
> > element in the non-existant array after the current one,
> > which is also the "pend" address for the array that
> > actually exists.


Again, it is not derefenced...

The type of my_array is int[]
The type of &my_array is int (*)[]
The type of &my_array + 1 is int (*)[]
The type of *(&my_array + 1) is int []

The last expression will decay to an int * when used in the
assignment to pend. At no stage is that pointer dereferenced.

--
Peter
 
Reply With Quote
 
vippstar@gmail.com
Guest
Posts: n/a
 
      02-06-2008
On Feb 6, 4:15 am, Peter Nilsson <(E-Mail Removed)> wrote:
> (E-Mail Removed) wrote:
> > Peter Nilsson <(E-Mail Removed)> wrote:
> > > ...
> > > int *p = my_array;
> > > int const *const pend = my_array + sizeof my_array/
> > > sizeof*my_array;
> > > do *p++ = 42;
> > > while (pend != p);

>
> > > At no stage is pend dereferenced; and the loop exits on
> > > p == pend, so the address is not dereferenced by p
> > > either.

>
> > Ah, I was a bit confused I guess.
> > However, OP _does_ dereference it. Not in that snipped,
> > but in 4)

>
> > > 4) *(&my_array+ 1) decays to the address of the first
> > > element in the non-existant array after the current one,
> > > which is also the "pend" address for the array that
> > > actually exists.

>
> Again, it is not derefenced...
>
> The type of my_array is int[]
> The type of &my_array is int (*)[]
> The type of &my_array + 1 is int (*)[]
> The type of *(&my_array + 1) is int []
>
> The last expression will decay to an int * when used in the
> assignment to pend. At no stage is that pointer dereferenced.

What i ment is that (&myarray + 1) is dereferenced, which would be
invalid, and if my reply to mr Thompson is correct, then even
computing &my_array+1 is invalid.
Remember; We are no longer talking about arrays but pointers, the
pointer-after-the-last-element rule does not apply.
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Is there a way to get a method to always run at the end of anydescendent's initialize method? Xeno Campanoli Ruby 9 02-14-2010 03:49 AM
Neatest way to do a case insensitive "in"? tinnews@isbd.co.uk Python 11 03-19-2009 11:16 PM
neatest way to extend Struct Martin DeMello Ruby 9 10-23-2008 07:19 AM
Measure delay end-to-end Dave Cisco 1 07-20-2004 12:51 PM
is there a difference between CIR and CIR+end to end clear channel connection? ike lozada Cisco 0 05-27-2004 02:34 AM



Advertisments