Velocity Reviews > Can I tab[-1] ?

# Can I tab[-1] ?

Shao Miller
Guest
Posts: n/a

 12-20-2012
On 12/20/2012 03:34, Robert Wessel wrote:
>
> I think you can do something like this:
>
> int a[12][12];
>
> void f()
> {
> int (*b)[10][12]; // note: use only 0..9 in second index
>
> b = (int (*)[10][12])&(a[1][1]);
>
> (*b)[2][2] = 3;
> }
>
> Given that the array layout is standardized, I *think* that doesn't
> violate any rules. You'd have a row and column of "pad" around the
> 10x10 array.
>
> I'm less confident that using a -1 as an index is guaranteed to work,
> but I think it might be.
>
> I'm less convinced that it's a good idea, though...
>

(*b)[-1]
*(*b - 1)

In this context, '*b' has type 'int[10][12]' but yields an 'int(*)[12]'.
Regardless of that, since 'b' points to an array, I believe that '*b -
1' is out of bounds. I think the cast could discard "the actual" bounds
and establish new ones; possibly interpreted by the implementation as an
instruction to forget what it knew.

- Shao Miller

Ben Bacarisse
Guest
Posts: n/a

 12-20-2012
Philip Lantz <(E-Mail Removed)> writes:

> fir wrote:
>> Also - I think if try to use some way of optimization
>> where instead of checking some edge values like
>>
>> if(x>=0 && x<500 && y>=0 && y<500)
>> tab[y][x] = 1;
>>
>> alloc some edge ram and do not bother about x=-1 or x=tab_max_x+1
>>
>> but here it would be convenient to cast some pointer to type
>> tab[500][500] 'into' wider_tab[502][502] in such way that
>> tab[0][0] would correspond to wider_tab[1][1] (and tab[-1][-1]
>> to wider_tab[0][0])

>
> int wider_tab[501*501+1];
> int (*tab)[500] = (int (*)[500])&wider_tab[500+1];
>
> tab[0][0] is wider_tab[501]
> tab[1][0] is wider_tab[1001]
> tab[500][500] is wider_tab[501*501]
> tab[-1][-1] is wider_tab[0]

I think the OP wants an 'dead' edge all the way round. I.e. I think
they want:

int wider_tab[(N+2)*(N+2)];
int (*tab)[N+2] = (int (*)[N+2])&wider_tab[N+2+1];

(for N=500). You could also (probably) get away with using plain 2D
arrays for a little more clarity:

int wider_tab[N+2][N+2];
int (*tab)[N+2] = (void *)&wider_tab[1][1];

For illustration, when N=5, the output of

memset(wider_tab, -1, sizeof wider_tab); // ok, know...
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
tab[i][j] = i*10 + j;
for (int i = 0; i < N+2; i++, putchar('\n'))
for (int j = 0; j < N+2; j++)
printf("%3d", wider_tab[i][j]);

would be:

-1 -1 -1 -1 -1 -1 -1
-1 0 1 2 3 4 -1
-1 10 11 12 13 14 -1
-1 20 21 22 23 24 -1
-1 30 31 32 33 34 -1
-1 40 41 42 43 44 -1
-1 -1 -1 -1 -1 -1 -1

<snip warnings>
--
Ben.

fir
Guest
Posts: n/a

 12-20-2012
W dniu czwartek, 20 grudnia 2012 14:38:45 UTC+1 użytkownik Ben Bacarisse napisał:
> Philip Lantz <(E-Mail Removed)> writes:
>
>
>
> > fir wrote:

>
> >> Also - I think if try to use some way of optimization

>
> >> where instead of checking some edge values like

>
> >>

>
> >> if(x>=0 && x<500 && y>=0 && y<500)

>
> >> tab[y][x] = 1;

>
> >>

>
> >> alloc some edge ram and do not bother about x=-1 or x=tab_max_x+1

>
> >>

>
> >> but here it would be convenient to cast some pointer to type

>
> >> tab[500][500] 'into' wider_tab[502][502] in such way that

>
> >> tab[0][0] would correspond to wider_tab[1][1] (and tab[-1][-1]

>
> >> to wider_tab[0][0])

>
> >

>
> > int wider_tab[501*501+1];

>
> > int (*tab)[500] = (int (*)[500])&wider_tab[500+1];

>
> >

>
> > tab[0][0] is wider_tab[501]

>
> > tab[1][0] is wider_tab[1001]

>
> > tab[500][500] is wider_tab[501*501]

>
> > tab[-1][-1] is wider_tab[0]

>
>
>
> I think the OP wants an 'dead' edge all the way round. I.e. I think
>
> they want:
>
>
>
> int wider_tab[(N+2)*(N+2)];
>
> int (*tab)[N+2] = (int (*)[N+2])&wider_tab[N+2+1];
>
>
>
> (for N=500). You could also (probably) get away with using plain 2D
>
> arrays for a little more clarity:
>
>
>
> int wider_tab[N+2][N+2];
> int (*tab)[N+2] = (void *)&wider_tab[1][1];
>

that is exactly what i want, but here above is it vector of pointers or lite/solid block of addresable ram (with no other area pointers?),
(somewhat sad to say but i forgot of was atways somewhat out to array pointer subtlities :/ like this)
what way "int (*tab)[N+2]" should be read?

>
>
> For illustration, when N=5, the output of
>
>
>
> memset(wider_tab, -1, sizeof wider_tab); // ok, know...
>
> for (int i = 0; i < N; i++)
>
> for (int j = 0; j < N; j++)
>
> tab[i][j] = i*10 + j;
>
> for (int i = 0; i < N+2; i++, putchar('\n'))
>
> for (int j = 0; j < N+2; j++)
>
> printf("%3d", wider_tab[i][j]);
>
>
>
> would be:
>
>
>
> -1 -1 -1 -1 -1 -1 -1
>
> -1 0 1 2 3 4 -1
>
> -1 10 11 12 13 14 -1
>
> -1 20 21 22 23 24 -1
>
> -1 30 31 32 33 34 -1
>
> -1 40 41 42 43 44 -1
>
> -1 -1 -1 -1 -1 -1 -1
>
>
>
> <snip warnings>
>
> --
>
> Ben.

Tim Rentsch
Guest
Posts: n/a

 12-20-2012
fir <(E-Mail Removed)> writes:

> Can I use c arrays in such way tab[-1] or tab[-1][-1] (I mean when index is below zero)?
>
> Also - I think if try to use some way of optimization
> where instead of checking some edge values like
>
> if(x>=0 && x<500 && y>=0 && y<500)
> tab[y][x] = 1;
>
> alloc some edge ram and do not bother about x=-1 or x=tab_max_x+1
>
> but here it would be convenient to cast some pointer ot type tab[500][500] 'into' wider_tab[502][502]
> in such way that tab[0][0] wolul correspond to wider_tab[1][1] (and tab[-1][-1] to wider_tab[0][0])
>
> Can I get something like that? (If not I am sad)

The short answer is no. If E is any expression of array type,
any use of (E)[-1] or even just ((E)-1) is undefined behavior.

To get something like what you want, you would have to use
an array of pointers, those pointers being of type (int *),
and the type of 'tab' being (int **), with tab pointing at
the second element of the array (ie, at index [1]). The
pointers in the pointer array should point into a large
one-dimensional array, eg, 'int tab_space[ 502 * 502 ];'.

fir
Guest
Posts: n/a

 12-20-2012
W dniu czwartek, 20 grudnia 2012 18:12:44 UTC+1 użytkownik Tim Rentschnapisał:
> fir <(E-Mail Removed)> writes:
>
>
>
> > Can I use c arrays in such way tab[-1] or tab[-1][-1] (I mean when index is below zero)?

>
> >

>
> > Also - I think if try to use some way of optimization

>
> > where instead of checking some edge values like

>
> >

>
> > if(x>=0 && x<500 && y>=0 && y<500)

>
> > tab[y][x] = 1;

>
> >

>
> > alloc some edge ram and do not bother about x=-1 or x=tab_max_x+1

>
> >

>
> > but here it would be convenient to cast some pointer ot type tab[500][500] 'into' wider_tab[502][502]

>
> > in such way that tab[0][0] wolul correspond to wider_tab[1][1] (and tab[-1][-1] to wider_tab[0][0])

>
> >

>
> > Can I get something like that? (If not I am sad)

>
>
>
> The short answer is no. If E is any expression of array type,
>
> any use of (E)[-1] or even just ((E)-1) is undefined behavior.
>
>
>
> To get something like what you want, you would have to use
>
> an array of pointers, those pointers being of type (int *),
>
> and the type of 'tab' being (int **), with tab pointing at
>
> the second element of the array (ie, at index [1]). The
>
> pointers in the pointer array should point into a large
>
> one-dimensional array, eg, 'int tab_space[ 502 * 502 ];'.

what with

int (*tab)[N+2] = (void *)&wider_tab[1][1];

isnt tab here a pointer to "int somechunk[502]" ?

and if so, tab+1 (or tab[1]) woluld be next one "int some[502}" laying after previous -

so if it is working -> (tab[j])[i] (or tab[j][i]), it should be working theway I would exactly like- so it would be grrt (great I mean)

as to -1 as far as i remember ritche wrote
(in c development historical note) that this
square bracket syntax is only a sugar/alias
to pointers *(a+5) becomes a[5] here (or even
5[a] points the same as denoted in wiki - so it is maybe just mechanical trick), so
by analogy if *(a-1) works a[-1] should be working also

Shao Miller
Guest
Posts: n/a

 12-20-2012
On 12/20/2012 12:30, fir wrote:
> W dniu czwartek, 20 grudnia 2012 18:12:44 UTC+1 użytkownik Tim Rentsch napisał:
>> The short answer is no. If E is any expression of array type,
>> any use of (E)[-1] or even just ((E)-1) is undefined behavior.
>>

>
> as to -1 as far as i remember ritche wrote
> (in c development historical note) that this
> square bracket syntax is only a sugar/alias
> to pointers *(a+5) becomes a[5] here (or even
> 5[a] points the same as denoted in wiki - so it is maybe just mechanical trick), so
> by analogy if *(a-1) works a[-1] should be working also
>

It is important to carefully note what Tim said about the type of 'E'.
If 'E' is a _pointer_, that's different than if 'E' is an _array_ which
happens to yield a pointer value in some contexts.

If 'E' is an array, the pointer value it yields (when it's not the
immediate operand of unary '&' or 'sizeof') is pointing to the lower
bound for the array. Subtracting 1 from that pointer value is thus
undefined behaviour, even if there so happens to be an object with
suitable type (or any type) available immediately before the array.

- Shao Miller

Shao Miller
Guest
Posts: n/a

 12-20-2012
On 12/20/2012 13:17, Shao Miller wrote:
> It is important to carefully note what Tim said about the type of 'E'.

Apologies. I meant Mr. T. Rentsch.

>
> If 'E' is an array, the pointer value it yields (when it's not the
> immediate operand of unary '&' or 'sizeof') [...]

Apologies. I forgot C11's '_Alignof', too.

- Shao Miller

Philip Lantz
Guest
Posts: n/a

 12-20-2012
Robert Wessel wrote:
> fir wrote:
> >Can I use c arrays in such way tab[-1] or tab[-1][-1] (I mean when
> >index is below zero)?
> >
> >Also - I think if try to use some way of optimization
> >where instead of checking some edge values like
> >
> >if(x>=0 && x<500 && y>=0 && y<500)
> > tab[y][x] = 1;
> >
> >alloc some edge ram and do not bother about x=-1 or x=tab_max_x+1
> >
> >but here it would be convenient to cast some pointer to type
> >tab[500][500] 'into' wider_tab[502][502] in such way that
> >tab[0][0] would correspond to wider_tab[1][1] (and tab[-1][-1]
> >to wider_tab[0][0])

>
>
> I think you can do something like this:
>
> int a[12][12];
>
> void f()
> {
> int (*b)[10][12]; // note: use only 0..9 in second index
>
> b = (int (*)[10][12])&(a[1][1]);
>
> (*b)[2][2] = 3;
> }
>
> Given that the array layout is standardized, I *think* that doesn't
> violate any rules. You'd have a row and column of "pad" around the
> 10x10 array.

If you don't need to be able to use a negative index in the second
dimension, you can do this without a cast, and the behavior is
definitely guaranteed:

int a[12][12];
int (*b)[12] = &a[1];

b[-1][0] is a[0][0]
b[0][0] is a[1][0]

> I'm less confident that using a -1 as an index is guaranteed to work,
> but I think it might be.

Using -1 as an index in a one-dimensional array is guaranteed to work:

int a[12];
int *b = &a[1];
b[-1] /* This is guaranteed to access a[0]. */

With a multi-dimensional array, it is less clear that the behavior is
guaranteed when using -1 as an index for anything other than the last
dimension, but I think it is, and even if it is not guaranteed by the
standard, I believe it is guaranteed by all implementations.

Tim Rentsch
Guest
Posts: n/a

 12-20-2012
fir <(E-Mail Removed)> writes:

> [citation for Tim Rentsch]
>> fir <(E-Mail Removed)> writes:
>>
>>
>>
>> > Can I use c arrays in such way tab[-1] or tab[-1][-1] (I mean when index is below zero)?

>>
>> >

>>
>> > Also - I think if try to use some way of optimization

>>
>> > where instead of checking some edge values like

>>
>> >

>>
>> > if(x>=0 && x<500 && y>=0 && y<500)

>>
>> > tab[y][x] = 1;

>>
>> >

>>
>> > alloc some edge ram and do not bother about x=-1 or x=tab_max_x+1

>>
>> >

>>
>> > but here it would be convenient to cast some pointer ot type tab[500][500] 'into' wider_tab[502][502]

>>
>> > in such way that tab[0][0] wolul correspond to wider_tab[1][1] (and tab[-1][-1] to wider_tab[0][0])

>>
>> >

>>
>> > Can I get something like that? (If not I am sad)

>>
>>
>>
>> The short answer is no. If E is any expression of array type,
>>
>> any use of (E)[-1] or even just ((E)-1) is undefined behavior.
>>
>>
>>
>> To get something like what you want, you would have to use
>>
>> an array of pointers, those pointers being of type (int *),
>>
>> and the type of 'tab' being (int **), with tab pointing at
>>
>> the second element of the array (ie, at index [1]). The
>>
>> pointers in the pointer array should point into a large
>>
>> one-dimensional array, eg, 'int tab_space[ 502 * 502 ];'.

Dear Professor:

get rid of extraneous blank lines.

> what with
>
> int (*tab)[N+2] = (void *)&wider_tab[1][1];
>
> isnt tab here a pointer to "int somechunk[502]" ?
>
> and if so, tab+1 (or tab[1]) woluld be next one "int some[502}" laying
> after previous -
>
> so if it is working -> (tab[j])[i] (or tab[j][i]), it should be
> working the way I would exactly like- so it would be grrt (great I
> mean)

Indexing in C is not defined just in terms of address
calculation. Address calculation is one aspect, but there
are additional constraints, and those constraints must be
observed; otherwise ALL BETS ARE OFF. The approach
described above violates those constraints. ANY approach
using pointer to array types, that attempts to index an
expression of array type with an index value of -1, will
violate the constraints. There is NO WAY to do what you
want to do using regular arrays or pointers to arrays; use
an array of pointers, and use type (int **) for the
accessing identifer ('tab' in the above) instead.

> as to -1 as far as i remember ritche wrote (in c development
> historical note) that this square bracket syntax is only a
> sugar/alias to pointers *(a+5) becomes a[5] here (or even 5[a]
> points the same as denoted in wiki - so it is maybe just
> mechanical trick), so by analogy if *(a-1) works a[-1] should be
> working also

C is now defined by the ISO document on it. Any writing by
Ritchie, however much we might enjoy or appreciate it, is no
longer authoritative.

Tim Rentsch
Guest
Posts: n/a

 12-20-2012
Philip Lantz <(E-Mail Removed)> writes:

> Robert Wessel wrote:
>> fir wrote:
>> >Can I use c arrays in such way tab[-1] or tab[-1][-1] (I mean when
>> >index is below zero)?
>> >
>> >Also - I think if try to use some way of optimization
>> >where instead of checking some edge values like
>> >
>> >if(x>=0 && x<500 && y>=0 && y<500)
>> > tab[y][x] = 1;
>> >
>> >alloc some edge ram and do not bother about x=-1 or x=tab_max_x+1
>> >
>> >but here it would be convenient to cast some pointer to type
>> >tab[500][500] 'into' wider_tab[502][502] in such way that
>> >tab[0][0] would correspond to wider_tab[1][1] (and tab[-1][-1]
>> >to wider_tab[0][0])

>>
>>
>> I think you can do something like this:
>>
>> int a[12][12];
>>
>> void f()
>> {
>> int (*b)[10][12]; // note: use only 0..9 in second index
>>
>> b = (int (*)[10][12])&(a[1][1]);
>>
>> (*b)[2][2] = 3;
>> }
>>
>> Given that the array layout is standardized, I *think* that doesn't
>> violate any rules. You'd have a row and column of "pad" around the
>> 10x10 array.

>
> If you don't need to be able to use a negative index in the second
> dimension, you can do this without a cast, and the behavior is
> definitely guaranteed:
>
> int a[12][12];
> int (*b)[12] = &a[1];
>
> b[-1][0] is a[0][0]
> b[0][0] is a[1][0]

Only because the expression being indexed with -1 is of pointer
type rather than array type.

>> I'm less confident that using a -1 as an index is guaranteed to work,
>> but I think it might be.

>
> Using -1 as an index in a one-dimensional array is guaranteed to work:
>
> int a[12];
> int *b = &a[1];
> b[-1] /* This is guaranteed to access a[0]. */

Again, only because the expression being indexed with -1 is of
pointer type rather than array type. If b were declared as

int (*b)[11] = (void*)&a[1];

then trying to access (*b)[-1] is undefined behavior.

> With a multi-dimensional array, it is less clear that the behavior is
> guaranteed when using -1 as an index for anything other than the last
> dimension,

Presumably you meant for anything other than the first dimension.

> but I think it is,

Any access through an array type must have an index value within
the bounds of the type of the array. An index value of -1 never
qualifies.

> and even if it is not guaranteed by the standard, I believe it
> is guaranteed by all implementations.

What I think you mean is that all implementations do in fact
produce (at the present time) the desired behavior. Even if
that's true, I expect no implementation actually guarantees it,
and certainly not all of them do.

 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 OffTrackbacks are On Pingbacks are On Refbacks are Off Forum Rules

 Similar Threads Thread Thread Starter Forum Replies Last Post Casey Hawthorne Java 1 03-18-2009 12:56 AM Martin Computer Support 16 02-24-2009 07:35 PM 02befree Computer Support 0 12-24-2007 09:10 PM jameshanley39@yahoo.co.uk Computer Information 2 09-19-2007 02:53 AM =?Utf-8?B?RGFuaWVsIEVpY2hvcm4=?= Wireless Networking 3 11-18-2004 11:03 PM