# Can I tab[-1] ?

Discussion in 'C Programming' started by fir, Dec 20, 2012.

1. ### firGuest

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)

fir, Dec 20, 2012

2. ### glen herrmannsfeldtGuest

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

Not with actual arrays, but you can with pointers and arrays
of pointers.

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

There is much discussion about pointers outside the allocated
space, such that the offset is inside. In this case, though,
the pointer is inside the allocated space, such that adding -1
is still inside.

-- glen

glen herrmannsfeldt, Dec 20, 2012

3. ### firGuest

W dniu czwartek, 20 grudnia 2012 08:43:49 UTC+1 uÅ¼ytkownik glen herrmannsfeldt napisaÅ‚:
> 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

> Not with actual arrays, but you can with pointers and arrays
> of pointers.
>
>
>
> > 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)

>
>
>
> There is much discussion about pointers outside the allocated
> space, such that the offset is inside. In this case, though,
> the pointer is inside the allocated space, such that adding -1
> is still inside.
>
>

you sure i cant do it with some static array[][] cast? I want such syntax tab[][] and also
i need natural coordinates 0-500 for centre plus -1 and 501 for additional border, also I wnt efficiency - adequate simple casting would be the best, though i do anderstand that i should cast on something like tab[502][502]
with somme offset (not tab[500][500]) and then
used it in tab[-1 to 501 included] so I just need recast tab[502][502] a 503 fields further

as to array of pointers with same syntax of usage t[j] - is it more efficient or less
(it is very important question and i still not sure)

fir, Dec 20, 2012
4. ### Philip LantzGuest

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]

There is a caveat: It's possible that the standard allows (int [500]) to
have a stricter alignment requirement than (int [502*502]), which would
mean that the cast isn't guaranteed to behave. I'm not convinced that
it's allowed, and even if it is, I am confident that no implementation
actually has such a requirement.

It's also possible that an implementation for x86 in huge model (where
arrays can span multiple segments), or similar architectures, could have
trouble with this, if the compiler was doing some very sophisticated
optimizations based on knowledge of how the array boundaries line up
with with segment boundaries. The normal brute force approach to huge
model shouldn't have any problem with it, though.

Philip Lantz, Dec 20, 2012
5. ### glen herrmannsfeldtGuest

fir <> wrote:
>> fir <> wrote:
>> > Can I use c arrays in such way tab[-1] or tab[-1][-1]
>> > (I mean when index is below zero)?

(snip)

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

(snip, then I wrote)
>> Not with actual arrays, but you can with pointers and arrays
>> of pointers.

>> > 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])

(snip)

> you sure i cant do it with some static array[][] cast?
> I want such syntax tab[][] and also i need natural coordinates
> 0-500 for centre plus -1 and 501 for additional border,
> also I wnt efficiency - adequate simple casting would be the best,
> though i do anderstand that i should cast on something
> like tab[502][502] with somme offset (not tab[500][500]) and then
> used it in tab[-1 to 501 included] so I just need recast
> tab[502][502] a 503 fields further

In the 1D case, you set a pointer to element 1, then all will
be off by one.

int tab1[503];
int *tab=tab+1;

Now tab[-1] through tab[501] exist. In most cases, the speed should
be the same.

> as to array of pointers with same syntax of usage
> t[j] - is it more efficient or less
> (it is very important question and i still not sure)

In the 2D case, you have an array of pointers to arrays, which
you can either generate pointers to existing arrays, or dynamically
allocate them:

int **tab2;
tab2=malloc(503*sizeof(*tab2))+1;
for(i=-1;i<502;i++) tab2=malloc(503*sizeof(**tab2))+1;

Often it is done this way to allow for dynamic allocation, and
not for efficiency reasons. It is a little hard to say which is
more efficient, as it depends much on the processor, memory cache,
and instruction overlap.

(Note that -1 through 501 is 503 elements, not 502.)

-- glen

glen herrmannsfeldt, Dec 20, 2012
6. ### glen herrmannsfeldtGuest

Philip Lantz <> wrote:

(snip)

>> 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])

(snip)

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

> There is a caveat: It's possible that the standard allows (int [500]) to
> have a stricter alignment requirement than (int [502*502]), which would
> mean that the cast isn't guaranteed to behave. I'm not convinced that
> it's allowed, and even if it is, I am confident that no implementation
> actually has such a requirement.

Sometimes it is nice to have something aligned higher than the
normal alignment, such as when using SSE modes that require 16 byte
alignment. In most cases, though, it is up to the programmer to keep
things aligned, not the compiler.

> It's also possible that an implementation for x86 in huge model (where
> arrays can span multiple segments), or similar architectures, could have
> trouble with this, if the compiler was doing some very sophisticated
> optimizations based on knowledge of how the array boundaries line up
> with with segment boundaries.

Yes, but in that case an array of large model pointers is a better choice.

> The normal brute force approach to huge model shouldn't have any
> problem with it, though.

Besides, since the 80386 segments are up to 4GB, and pretty much no
systems support even large model in 32 bit mode.

(Yes, I did much work on the 80286 using arrays of far pointers.)

-- glen

glen herrmannsfeldt, Dec 20, 2012
7. ### glen herrmannsfeldtGuest

Robert Wessel <> wrote:

(snip)

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

I believe it pretty much has to work. The other way around, subtracting
from a pointer to allow the low end of an array to be 1 is not
guaranteed to work, but was used in "Numerical Recipes in C" to make
translation from Fortran to C easier.

> I'm less convinced that it's a good idea, though...

Hard to say.

-- glen

glen herrmannsfeldt, Dec 20, 2012
8. ### Shao MillerGuest

On 12/20/2012 03:28, Philip Lantz wrote:
>
> There is a caveat: It's possible that the standard allows (int [500]) to
> have a stricter alignment requirement than (int [502*502]), which would
> mean that the cast isn't guaranteed to behave. I'm not convinced that
> it's allowed, and even if it is, I am confident that no implementation
> actually has such a requirement.
>

Confidence: Agreed.

C11's 6.2.8p4 seems to suggest that possible alignments are really
derived from fundamental types.

It'd seem odd if 'malloc(sizeof (int[502 * 502]))' had to worry about
satisfying the possibility that you might be overallocating, but really
interested in using the storage for an 'int[500]' with a stricter
requirement than an 'int[502 * 502]'.

- Shao Miller

Shao Miller, Dec 20, 2012
9. ### firGuest

W dniu czwartek, 20 grudnia 2012 10:16:48 UTC+1 uÅ¼ytkownik glen herrmannsfeldt napisaÅ‚:
> Robert Wessel <> wrote:
>
>
> > I'm less convinced that it's a good idea, though...

>
>
> Hard to say.
>

not to much hard to say ;-) it is good

can be usefull as in my example of :

x, y are random coordinates from x: -10 to 650, y: -10 to 500, there are large amounts of them only some are out of 0-640 0-480

you dont want to if(x>=0 && x<640 && y>=0 && y<480) ... on thousands ofthem just need to alloc little more and if you can 'recast' it
you can use natural coordinates (same as with pure method with if() checking/clipping,

so imo it is welcome in c

fir, Dec 20, 2012
10. ### Shao MillerGuest

On 12/20/2012 01:25, fir wrote:
> Can I use c arrays in such way tab[-1] or tab[-1][-1] (I mean when index is below zero)?
>

I'd say it depends on the declaration. It is not clear from this
question what the types of 'tab[-1]' or 'tab[-1][-1]' are expected to be.

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

I don't see any allocation. Could you share the bit of code that does
the allocation?

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

I'd say it depends on the declarations involved. It is not clear if you
are working with an array of pointers or not, for example.

You might or might not be interested in "Multi-Dimensional Array
Simulator" at http://www.iso-9899.info/wiki/Code_snippets

- Shao Miller

Shao Miller, Dec 20, 2012
11. ### Shao MillerGuest

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

Shao Miller, Dec 20, 2012
12. ### Ben BacarisseGuest

Philip Lantz <> 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[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[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.

Ben Bacarisse, Dec 20, 2012
13. ### firGuest

W dniu czwartek, 20 grudnia 2012 14:38:45 UTC+1 uÅ¼ytkownik Ben Bacarisse napisaÅ‚:
> Philip Lantz <> 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[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[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, Dec 20, 2012
14. ### Tim RentschGuest

fir <> 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 ];'.

Tim Rentsch, Dec 20, 2012
15. ### firGuest

W dniu czwartek, 20 grudnia 2012 18:12:44 UTC+1 uÅ¼ytkownik Tim RentschnapisaÅ‚:
> fir <> 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]) (or tab[j]), 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

fir, Dec 20, 2012
16. ### Shao MillerGuest

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, Dec 20, 2012
17. ### Shao MillerGuest

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

Shao Miller, Dec 20, 2012
18. ### Philip LantzGuest

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.

Philip Lantz, Dec 20, 2012
19. ### Tim RentschGuest

fir <> writes:

> [citation for Tim Rentsch]
>> fir <> 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]) (or tab[j]), 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, Dec 20, 2012
20. ### Tim RentschGuest

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

Tim Rentsch, Dec 20, 2012