Is out-of-bounds portable on a multidimensional array?

A

ais523

I've checked the FAQ for this and couldn't find the answer. Is the
following code snippet portable?

int a[10][10];
a[1][4]=6;
printf("%d\n",(*a)[14]);

This prints "6" on my compiler. I've been told it's always legal, but
it seems slightly suspect to me. Can you really go out-of-bounds like
this on one of the 'sub-arrays' a[0], a[1], etc.?

(N.B. To the pedants out there: this is not meant to be a complete
program, just part of one.)
 
F

Flash Gordon

ais523 said:
I've checked the FAQ for this and couldn't find the answer. Is the
following code snippet portable?

int a[10][10];
a[1][4]=6;
printf("%d\n",(*a)[14]);

This prints "6" on my compiler. I've been told it's always legal, but
it seems slightly suspect to me. Can you really go out-of-bounds like
this on one of the 'sub-arrays' a[0], a[1], etc.?

This has been discussed here before at length with strong opinions in
moth directions. I think that it is technically undefined behaviour but
will only fail on implementations that go out of their way to do bounds
checking.

I think that the following might be OK though:
int a[10][10];
a[1][4]=6;
printf("%d\n",((int*)a)[14]);
A rough reasoning being that a must be properly aligned for an int*, so
we know the conversion will work and also obviously know it will point
to the first element of the first sub-array. Also the size of an array
is guaranteed to be the number of elements times the size of each
elements, which does not leave any room for padding to be inserted.
Finally, the array a is one object, so we are not leaving the object we
are pointing to.

Note, the last of these does not necessarily apply without the cast to
int* because a[0] is an object of type array of 10 ints.

Personally, I would be very dubious of code doing this unless there was
a very good justification for not treating it as a 2d array.
(N.B. To the pedants out there: this is not meant to be a complete
program, just part of one.)

You've obviously been reading this group since you've realised it is
full of pedants :)
 
S

serrand

Flash said:
ais523 said:
I've checked the FAQ for this and couldn't find the answer. Is the
following code snippet portable?

int a[10][10];
a[1][4]=6;
printf("%d\n",(*a)[14]);

This prints "6" on my compiler. I've been told it's always legal, but
it seems slightly suspect to me. Can you really go out-of-bounds like
this on one of the 'sub-arrays' a[0], a[1], etc.?


This has been discussed here before at length with strong opinions in
moth directions. I think that it is technically undefined behaviour but
will only fail on implementations that go out of their way to do bounds
checking.

I think that the following might be OK though:
int a[10][10];
a[1][4]=6;
printf("%d\n",((int*)a)[14]);
A rough reasoning being that a must be properly aligned for an int*, so
we know the conversion will work and also obviously know it will point
to the first element of the first sub-array. Also the size of an array
is guaranteed to be the number of elements times the size of each
elements, which does not leave any room for padding to be inserted.
Finally, the array a is one object, so we are not leaving the object we
are pointing to.

Note, the last of these does not necessarily apply without the cast to
int* because a[0] is an object of type array of 10 ints.

Personally, I would be very dubious of code doing this unless there was
a very good justification for not treating it as a 2d array.
(N.B. To the pedants out there: this is not meant to be a complete
program, just part of one.)


You've obviously been reading this group since you've realised it is
full of pedants :)


when seeking a bi-dimensional array of char (argv) going out-of-bounds,
i had a segmentation fault long before then end of the array

/* FIRST SEEK argv : OK */
for (i=0; i<argc+1000; i++)
{
printf ("argv[%d] %s\n\n", i, argv);
if ((i>argc) && (*(argv+i) == NULL))
{
printf ("FIN de Tab arg %d\n\n", i);
break;
}
}

/* THIS SEEK (char)(*argv) : KO long before end of last array (69/86 but it depends on the previous code...) */
/* what's more seg fault occurs long after crossing from argv to envp... */
for (i=0; i<86*100; i++)
{
printf ("%c", (char)(*argv));
}

this trouble seems not occur with array of array of int ...

Xavier
 
F

Flash Gordon

serrand wrote:

<snip>

Your post did not have anything to do with mine. It is a completely
different situation.
when seeking a bi-dimensional array of char (argv) going out-of-bounds,
i had a segmentation fault long before then end of the array

argv is not a two-dimensional array, it is an array of pointers, a
*very* different thing. Read section 6 of the FAQ, particularly
questions 6.18 and 6.19
/* FIRST SEEK argv : OK */
for (i=0; i<argc+1000; i++)
{
printf ("argv[%d] %s\n\n", i, argv);


As soon as you hit the last element of argv you invoke undefined
behaviour since you pass a null pointer for the %s specifier. You invoke
it again as soon as you go beyond the end of argv.
if ((i>argc) && (*(argv+i) == NULL))
{
printf ("FIN de Tab arg %d\n\n", i);
break;
}
}

/* THIS SEEK (char)(*argv) : KO long before end of last array
(69/86 but it depends on the previous code...) */
/* what's more seg fault occurs long after crossing from argv to
envp... */
for (i=0; i<86*100; i++)
{
printf ("%c", (char)(*argv));
}

this trouble seems not occur with array of array of int ...


I ran across Church Road without checking if it was clear and nothing
went wrong, but when I ran across Daws Hearth Road without checking I
got hit by a 10 tonne lorry and was in hospital for a week! Why does
this only happen when running across Daws Heath Road?

Answer, blind luck.

Don't read or write off the end of an array. Every. You don't try to
read the 300th page of a 200 page book do you? Or put 200 galleons of
petrol in the petrol tank of your car which doesn't take that much? So
why do you think it is OK to do the same thing with arrays in C?
 
S

serrand

Flash said:
argv is not a two-dimensional array, it is an array of pointers, a
*very* different thing. Read section 6 of the FAQ, particularly
questions 6.18 and 6.19
thanks too much !! it's the explanation i expected ...

I ran across Church Road without checking if it was clear and nothing
went wrong, but when I ran across Daws Hearth Road without checking I
got hit by a 10 tonne lorry and was in hospital for a week! Why does
this only happen when running across Daws Heath Road?

Answer, blind luck.

Don't read or write off the end of an array. Every. You don't try to
read the 300th page of a 200 page book do you? Or put 200 galleons of
petrol in the petrol tank of your car which doesn't take that much? So
why do you think it is OK to do the same thing with arrays in C?

when reading out-of-bounds...don't we try to read the 300th page of a 200 page book ?
We can if next place is another book of the same kind ...
with bi-dimensional array, sub-arrays are contiguous... then we can pass the bounds...
the same occurs when we are certain that elements (arrays...) are contiguous...
with union don't we do that thing ?

struct TAddr {
union {
unsigned char octs[4];
unsigned long int num_ip;
} ip;
};

but i'm always following your advice (as faq 6.19) ;-)

Xavier
 
J

Jordan Abel

Flash said:
ais523 said:
I've checked the FAQ for this and couldn't find the answer. Is the
following code snippet portable?

int a[10][10];
a[1][4]=6;
printf("%d\n",(*a)[14]);

This prints "6" on my compiler. I've been told it's always legal, but
it seems slightly suspect to me. Can you really go out-of-bounds like
this on one of the 'sub-arrays' a[0], a[1], etc.?


This has been discussed here before at length with strong opinions in
moth directions. I think that it is technically undefined behaviour but
will only fail on implementations that go out of their way to do bounds
checking.

I think that the following might be OK though:
int a[10][10];
a[1][4]=6;
printf("%d\n",((int*)a)[14]);
A rough reasoning being that a must be properly aligned for an int*, so
we know the conversion will work and also obviously know it will point
to the first element of the first sub-array. Also the size of an array
is guaranteed to be the number of elements times the size of each
elements, which does not leave any room for padding to be inserted.
Finally, the array a is one object, so we are not leaving the object we
are pointing to.

Note, the last of these does not necessarily apply without the cast to
int* because a[0] is an object of type array of 10 ints.

Personally, I would be very dubious of code doing this unless there was
a very good justification for not treating it as a 2d array.
(N.B. To the pedants out there: this is not meant to be a complete
program, just part of one.)


You've obviously been reading this group since you've realised it is
full of pedants :)


when seeking a bi-dimensional array of char (argv) going out-of-bounds,
i had a segmentation fault long before then end of the array

argv is not a "bi-dimensional array" in the sense required for the
original question to apply.
 
R

relient

A multi-dimensional array is really just a single dimensional array
that lets itself be treated as a multi-dimensional one - it's stored in
memory contiguously - therefore allowing you do do what you just did. A
true multi-dimensional array is an array of pointers (some would argue
with this statement, though) - the memory layout is not contiguous,
excepet for the first index of course (..the pointers), and thus, you
would not be able to do the same out-of-bounds trick.
 
K

Keith Thompson

relient said:
A multi-dimensional array is really just a single dimensional array
that lets itself be treated as a multi-dimensional one - it's stored in
memory contiguously - therefore allowing you do do what you just did. A
true multi-dimensional array is an array of pointers (some would argue
with this statement, though) - the memory layout is not contiguous,
excepet for the first index of course (..the pointers), and thus, you
would not be able to do the same out-of-bounds trick.

Context please! Read <http://cfaj.freeshell.org/google/>.

A multi-dimensional array is really an array of arrays. The standard
says enough about array layouts that we can be sure the rows are
allocated contiguously. Given

int arr[5][5];

we can be sure that arr[0][7], *if it's legal*, is at the same
location as arr[1][2]. But there might be enough ambiguity in the
standard to allow an implementation to do bounds checking in a way
that allows arr[1][2], but forbids arr[0][7]. Or there might not;
this has been the subject of some debate, and as far as I know it
hasn't really been resolved.

An array of pointers is *not* a "true multi-dimensional array"; it's
just an array of pointers. It can be used to implement something that
acts very much like a multi-dimensional array, but it isn't one. The
standard is clear on this point.
 
F

Flash Gordon

serrand said:
Flash Gordon wrote:


when reading out-of-bounds...don't we try to read the 300th page of a
200 page book ?
We can if next place is another book of the same kind ...

In C there is no guarantee what order object will be stored.
with bi-dimensional array, sub-arrays are contiguous... then we can pass
the bounds...

That is more like going to a different chapter in the same book. See
also Keith Thompson's reply to relient.
the same occurs when we are certain that elements (arrays...) are
contiguous...
with union don't we do that thing ?

I'm really not sure what you are trying to say here.
struct TAddr {
union {
unsigned char octs[4];
unsigned long int num_ip;
} ip;
};

but i'm always following your advice (as faq 6.19) ;-)

Good.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top