sandeep said:
Keith Thompson writes: [...]
You need to understand what "undefined behavior" means. It doesn't mean
"the program will crash". It means, to quote C99 3.4.3:
behavior, upon use of a nonportable or erroneous program construct
or of erroneous data, for which this International Standard imposes
no requirements
"imposes no requirements". Nothing more, nothing less.
I would expect an undefined behavior to be segmentation fault, memory or
files overwritten, etc. If a program behaves correctly on all compilers,
I would call that a defined behavior!
Then your expectation is incorrect. That quite simply is not what the
phrase "undefined behavior" means. Please re-read what I wrote above,
and do not assume that any preconceived notions you might have are
necessarily correct, no matter how much sense they seem to make to you.
My understanding is that it is *guaranteed* that a multidimensional array
will be stored in a contiguous block of memory in rowmajor order. This is
certainly what my textbook says. Perhaps Mr. Sosmanji is making another
obscure point though?
Your understanding about the way multidimensional arrays are allocated
is correct. It follows from the fact that 1-dimensional arrays are
contiguous with no gaps (I don't actually have chapter-and-verse for
that off the top of my head) and that multidimensional arrays are
nothing more than arrays of arrays.
But it doesn't follow from this that an array indexing operation can
extend beyond the bounds of the array on which it's based.
The indexing operator [] is defined in terms of pointer arithmetic,
specifically the "+" operator whose operands are a pointer and
an integer (x[y] is equivalent to *(x+y)). The semantics of "+"
are explained in C99 6.5.6p8. In particular:
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.
Given the code in question:
int array[2][3] = { { 0, 1, 2 }, { 3, 4, 5 } };
int *p = &array[0][3]; // no problem
the "pointer operand" is ``&array[0]'', and the RHS of the implicit
"+" is 3. The "same array object" is the 0th element of ``array'',
which is of type int[3]. The addition itself is ok, since it
yields a pointer one past the last element of the array object,
but the behavior of dereferencing it is undefined. Yes, there's an
int object at that location, namely array[1][0], but *that doesn't
mean you can dereference the pointer*.
If the standard doesn't define the behavior, the behavior is
undefined (unless the implementation chooses to define it).
As for *why* it's not defined, here's an example. Suppose a
given CPU has an indexed addressing mode that allows an offset to
be specified in some particularly efficient way, but only for
offsets up to N bytes. For larger offsets, you need to perform
an explicit addition, which costs a couple of extra instructions
and some extra time. If the compiler sees an expression arr[x]
and it knows that x is no bigger than N bytes, it can use the more
efficient addressing mode. If x happens to be bigger than N,
then it doesn't work properly (maybe it wraps around, maybe it
melts the CPU). In effect, you lied to the compiler, implicitly
claiming that arr[x] doesn't go beyond the bounds of arr. And the
sad part is that you wrote the code 10 years ago, and it's worked
"correctly" ever since then, but it failed last week when the code
was recompiled for a new platform.
I'm not saying that this specific scenario is the rationale for
not defining array indexing beyond the bounds of an array, but this
is the general kind of thing you need to worry about -- or rather,
that you don't need to worry about if you stick to what the language
actually guarantees.
Incidentally, I realized after I snipped the quoted text that the C
code was mangled again. Please consult the documentation for your
newsreader and find out how to stop it from doing that.