How does this array subtraction work without assignment? - arrays

The array does not have any assigned values, but when subtracting the values in the array, the z value becomes 20.
Can anyone explain this concept?
Any help would be appreciated.
#include <stdio.h>
int main()
{
int a[10][20][30][40];
int z = a[6] - a[5];
printf("%d\n", z); // z value is 20. why?
}

I believe this is technically undefined behavior. At least in C++, probably in C as well.
In practice it will almost certainly print 20, as explained by other answers, but it violates C11 6.5.6 Additive operators / 9 (and in C++: [expr.add]/4.2):
When two pointers are subtracted, both shall point to elements of the same array object,
or one past the last element of the array object ...
Your pointers point to two different arrays: to the first elements of a[6] and a[5] respectively.
One could argue that the first element of a[6] is one past the last element of a[5], but at least in C++, it's not the case, even though they have the same value: notoriously, how a pointer was derived does matter (that's why things like std::launder exist).
A non-UB way of computing the same thing would be:
int z = ((uintptr_t)a[6] - (uintptr_t)a[5]) / sizeof(a[0][0]);
This is technically implementation-defined (because of pointer-to-uintptr_t conversion), but should have an even smaller chance of breaking.

z value is 20. why?
Given int a[10][20][30][40];, a[6] indicates an array, an array of 20 elements.
When used in subtraction like a[6] - a[5], the arrays are converted to the address of the type of their first elements. So it is like &a[6][0] - &a[5][0]. &a[6][0] is a pointer. The pointer type they share is not so important here.
Pointer subtraction returns the difference in elements as an integer of type ptrdiff_t. There are 20 elements between &a[6][0] and &a[5][0].
When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object; the result is the difference of the subscripts of the two array elements. The size of the result is implementation-defined, and its type (a signed integer type) is ptrdiff_t ... C17dr § 6.5.6 9
Code then assigns a 20 (of type ptrdiff_t) to z, an int.

Because it is pointer arithmetics.
a[6] is 20 elements of type int[30][40] from a[5].
It happens because arrays decay to pointers

The array does not have any assigned values, but when subtracting the values in the array, the z value becomes 20.
You are not subtracting any values in the array. Not int values, anyway.
This declaration ...
int a[10][20][30][40];
... says that a is an array of 10 (arrays of 20 (arrays of 30 (arrays of 40 int))).
Therefore a[5] and a[6] are each an array of 20 (arrays of 30 (arrays of 40 int)).
When array-valued expressions appear as operands in most kinds of expressions, they are automatically converted to pointers to their first elements, so a[6] - a[5] is equivalent to &a[6][0] - &a[5][0].
Pointer differences are computed in units the size of the pointed-to type, so it doesn't actually matter for this purpose what the type of a[5][0] and a[6][0] is, or what int values are stored in the a[i][j][k][l]. The value of the difference is fully determined by the second dimension of a, which is 20.

Related

Does C specify the memory format of a (static) many-dimensional array? [duplicate]

I imagine we all agree that it is considered idiomatic C to access a true multidimensional array by dereferencing a (possibly offset) pointer to its first element in a one-dimensional fashion, e.g.:
void clearBottomRightElement(int *array, int M, int N)
{
array[M*N-1] = 0; // Pretend the array is one-dimensional
}
int mtx[5][3];
...
clearBottomRightElement(&mtx[0][0], 5, 3);
However, the language-lawyer in me needs convincing that this is actually well-defined C! In particular:
Does the standard guarantee that the compiler won't put padding in-between e.g. mtx[0][2] and mtx[1][0]?
Normally, indexing off the end of an array (other than one-past the end) is undefined (C99, 6.5.6/8). So the following is clearly undefined:
struct {
int row[3]; // The object in question is an int[3]
int other[10];
} foo;
int *p = &foo.row[7]; // ERROR: A crude attempt to get &foo.other[4];
So by the same rule, one would expect the following to be undefined:
int mtx[5][3];
int (*row)[3] = &mtx[0]; // The object in question is still an int[3]
int *p = &(*row)[7]; // Why is this any better?
So why should this be defined?
int mtx[5][3];
int *p = &(&mtx[0][0])[7];
So what part of the C standard explicitly permits this? (Let's assume c99 for the sake of discussion.)
EDIT
Note that I have no doubt that this works fine in all compilers. What I'm querying is whether this is explicitly permitted by the standard.
All arrays (including multidimensional ones) are padding-free. Even if it's never explicitly mentioned, it can be inferred from sizeof rules.
Now, array subscription is a special case of pointer arithmetics, and C99 section 6.5.6, §8 states clearly that behaviour is only defined if the pointer operand and the resulting pointer lie in the same array (or one element past), which makes bounds-checking implementations of the C language possible.
This means that your example is, in fact, undefined behaviour. However, as most C implementations do not check bounds, it will work as expected - most compilers treat undefined pointer expressions like
mtx[0] + 5
identically to well-defined counterparts like
(int *)((char *)mtx + 5 * sizeof (int))
which is well-defined because any object (including the whole two-dimensional array) can always be treated as a one-dimensinal array of type char.
On further meditation on the wording of section 6.5.6, splitting out-of-bounds access into seemingly well-defined subexpression like
(mtx[0] + 3) + 2
reasoning that mtx[0] + 3 is a pointer to one element past the end of mtx[0] (making the first addition well-defined) and as well as a pointer to the first element of mtx[1] (making the second addition well-defined) is incorrect:
Even though mtx[0] + 3 and mtx[1] + 0 are guaranteed to compare equal (see section 6.5.9, §6), they are semantically different. For example, the former can't be dereferenced and thus does not point to an element of mtx[1].
The only obstacle to the kind of access you want to do is that objects of type int [5][3] and int [15] are not allowed to alias one another. Thus if the compiler is aware that a pointer of type int * points into one of the int [3] arrays of the former, it could impose array bounds restrictions that would prevent accessing anything outside that int [3] array.
You might be able to get around this issue by putting everything inside a union that contains both the int [5][3] array and the int [15] array, but I'm really unclear on whether the union hacks people use for type-punning are actually well-defined. This case might be slightly less problematic since you would not be type-punning individual cells, only the array logic, but I'm still not sure.
One special case that should be noted: if your type were unsigned char (or any char type), accessing the multi-dimensional array as a one-dimensional array would be perfectly well-defined. This is because the one-dimensional array of unsigned char that overlaps it is explicitly defined by the standard as the "representation" of the object, and is inherently allowed to alias it.
It is sure that there is no padding between the elements of an array.
There are provision for doing address computation in smaller size than the full address space. This could be used for instance in the huge mode of 8086 so that the segment part would not always be updated if the compiler knew that you couldn't cross a segment boundary. (It's too long ago for me to remind if the compilers I used took benefit of that or not).
With my internal model -- I'm not sure it is perfectly the same as the standard one and it is too painful to check, the information being distributed everywhere --
what you are doing in clearBottomRightElement is valid.
int *p = &foo.row[7]; is undefined
int i = mtx[0][5]; is undefined
int *p = &row[7]; doesn't compile (gcc agree with me)
int *p = &(&mtx[0][0])[7]; is in the gray zone (last time I checked in details something like this, I ended up by considering invalid C90 and valid C99, it could be the case here or I could have missed something).
My understanding of the C99 standard is that there is no requirement that multidimensional arrays must be laid out in a contiguous order in memory. Following the only relevant information I found in the standard (each dimension is guaranteed to be contiguous).
If you want to use the x[COLS*r + c] access, I suggest you stick to single dimension arrays.
Array subscripting
Successive subscript operators designate an element of a multidimensional array object.
If E is an n-dimensional array (n ≥ 2) with dimensions i × j × . . . × k, then E (used as
other than an lvalue) is converted to a pointer to an (n − 1)-dimensional array with
dimensions j × . . . × k. If the unary * operator is applied to this pointer explicitly, or
implicitly as a result of subscripting, the result is the pointed-to (n − 1)-dimensional array,
which itself is converted into a pointer if used as other than an lvalue. It follows from this
that arrays are stored in row-major order (last subscript varies fastest).
Array type
— An array type describes a contiguously allocated nonempty set of objects with a
particular member object type, called the element type.
36)
Array types are
characterized by their element type and by the number of elements in the array. An
array type is said to be derived from its element type, and if its element type is T , the
array type is sometimes called ‘‘array of T ’’. The construction of an array type from
an element type is called ‘‘array type derivation’’.

division during pointer subtraction in C

Consider below code snippet :
int *p;
/* Lets say p points to address 100
and sizeof(int) is 4 bytes. */
int *q = p+1;
unsigned long r = q-p;
/* r results in 1, hence for r = q-p
something is happening similar to r=(104-100)/4 */
Is there a real division by sizeof(datatype) going on during runtime when two pointers of same type are subtracted, or there is some other mechanism through which pointer subtraction works.
The C standard states the following regarding pointer subtraction (section 6.5.6p9):
When two pointers are subtracted, both shall point to elements of the
same array object, or one past the last element of the array
object; the result is the difference of the subscripts of the
two array elements. The size of the result is
implementation-defined, and its type (a signed integer type) is
ptrdiff_t defined in the header. If the result is not
representable in an object of that type, the behavior is
undefined. In other words, if the expressions P and Q point to,
respectively, the i
-th and j
-th elements of an array object, the expression (P)-(Q) has the value i−j provided the value fits in an object of type ptrdiff_t . Moreover,
if the expression P points either to an element of an array object or
one past the last element of an array object, and the expression Q
points to the last element of the same array object, the expression
((Q)+1)-(P) has the same value as ((Q)-(P))+1 and as
-((P)-((Q)+1)) , and has the value zero if the expression P points one past the last element of the array object, even
though the expression (Q)+1 does not point to an element of the array
object. 106)
Footnote 106 states:
Another way to approach pointer arithmetic is first to convert the
pointer(s) to character pointer(s): In this scheme the integer
expression added to or subtracted from the converted pointer is first
multiplied by the size of the object originally pointed to,
and the resulting pointer is converted back to the original
type. For pointer subtraction, the result of the difference
between the character pointers is similarly divided by the size of
the object originally pointed to. When viewed in this way, an
implementation need only provide one extra byte (which may
overlap another object in the program) just after the end of the
object in order to satisfy the "one past the last element"
requirements.
So the footnote states that pointer subtraction may be implemented by subtracting the raw pointer values and dividing by the size of the pointed-to object. It doesn't have to be implemented this way, however.
Note also that the standard requires that pointer subtraction is performed between pointers pointing to elements of the same array object (or one element past the end). If they don't then the behavior is undefined. In practice, if you're working on a system with a flat memory model you'll probably still get the "expected" values but you can't depend on that.
See #dbush answer for the explanation on how pointer substraction works.
If, instead, you are programming something low-level, say a kernel, driver, debugger or similar and you need to have actual subtraction of addresses, cast the pointers to char *:
(char *)q - (char *)p
The result will be of ptrdiff_t type, an implementation defined signed integer.
Of course, this is not defined/portable C, but will work on most architectures/environments.

C programming address for 2d array

If I initialized a 2d array let’s say
Int a[2][3] = {
1, 2, 3,
4, 5, 6};
Is a[0] == &a[0]??
I know a[0] refers to the address for the first element of the array. So is &a[0] still the address?
First of all, the type of arrayNum[0] is Int[3] and the type of &arrayNum[0] is Int(*)[3] (I didn't change the OP's Int to the probable int).
Secondly, arrays can decay to a pointer to its first element, so arrayNum[0] can decay to &arrayNum[0][0] which is of type Int*.
Both those pointers, &arrayNum[0] and &arrayNum[0][0] will point to the same location, but their types are very different.
I'm not sure what you meant to comapre using the == in your question, but let me tell you these, they are not the same.
Data type:
Check the data type.
a[0] is the first element of the array of type int [3].
&a[0] is the pointer to the first element of the array of type int [3], so, it is essentially int (*) [3].
Usage: Now, based on the usage, in certain cases Note, an "array type", decays to a pointer to it's first element. Considering that case, a[0] and &a[0], both are equivalent to writing &(a[0][0]), so the pointer value will be same.
For better understanding of the difference, use both a[0] and &a[0] as the argument yo sizeof operator (where the decay does not happen) and print the value using %zu conversion specifier.
Typically, they will print
12, which is (sizeof (int) * 3) and
8, which is sizeof (int (*) [3])
on a platform where size of an int is 4 and size of a pointer is 8.
[Note]:
Quoting C11, chapter §6.3.2.1
Except when it is the operand of the sizeof operator, the _Alignof operator, or the
unary& operator, or is a string literal used to initialize an array, an expression that has
type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points
to the initial element of the array object and is not an lvalue. [....]
There are two senses in which you might ask whether a[0] equals &a[0]:
Do a[0] and &a[0] point to the same place?
and:
Does a[0] == &a[0] evaluate to true?
It is not clear from your question which you mean. Your text asks “Is a[0] == &a[0]?” Since the “==” is not in code format, it is not clear whether you intended to exclude it.
The answer to the first question is yes (given that a[0] is automatically converted to an address), and the answer to the second question is not necessarily.
As other answers and comments have pointed out, a[0] and &a[0] are different things. a is an array of two arrays of three int. So a[0] is an array of three int, and, in most expressions, it is automatically converted to a pointer to its first element. So the result is a pointer to an int, effectively &a[0][0]. In contrast, &a[0] is the address of an array of three int.
So, these expressions point to two different objects, but the two objects start at the same location, so the pointers point to the same “place.” We can see this in:
(char *) a[0] == (char *) &a[0] // Evaluates to true.
When we convert a pointer to a pointer to char, the result points to the first (lowest addressed) byte of the object. Since the two pointers point to the same place, this expression will evaluate to true.
However, when you evaluate a[0] == &a[0], there is a problem. To conform to the C standard, a comparison of pointers must compare pointers to compatible types. But int and array of three int are not compatible types. So this comparison is not strictly conforming C, although some compilers may allow it, likely with a warning message. We can instead evaluate:
a[0] == (int *) &a[0] // Value is not specified.
By converting the pointer on the right to a pointer to int, we make the left and right sides have the same type, and we can compare them. However, the result of the comparison is not defined. This is because that, although the C standard allows us to convert a pointer to one type to a pointer to another type, it does not generally guarantee what the value that results from the conversion is, except that, if you convert it back to the original type, then it will compare equal to the original pointer. (Converting to a pointer to a character type is special; for those, the compiler does guarantee the result points to the first byte of the object.)
So, since we do not know what the value of (int *) &a[0] is, we do not know whether comparing it to a[0] will return true or false.
This might seem strange; if one address points to the same place as another address, why wouldn’t they compare equal? On some computers, there is more than one way of referring to the same place in memory. Addresses may actually be formed of comnbinations of parts, such as base addresses plus offsets. For example, the address (1000, 230), representing 1230, points to the same place as (1200, 30), also representing 1230. But clearly (1000, 230) is not the same as (1200, 30).
When you compare two pointers to the same type, the compiler automatically adjusts the representations of the addresses in whatever way it needs to to perform the comparison. But, when you convert a pointer to one type to a pointer to another (non-character) type, the change of types may prevent the compiler from having the information it needs to do this adjustment properly. So the C standard does not tell us what happens in this case.
No they are not the same.
a[0] is an element of type int[3], while &a[0] is a pointer (of type int*[3]) to a[0].
But both of them points to the same address (the first element of a[0]), but are not the same.

In C, is it guaranteed that the array start address is smaller than the other elements' addresses?

In other word when doing
index = &array[x] - &array[0];
Is it always guaranteed (per C standard) that &array[0] <= &array[x], or is it dependent on the compiler?
What are the C standard chapters relevant for this topic ?
The address ordering is guaranteed. The behaviour of relational operators is defined in C11 6.5.8p5:
[...] pointers to array elements with larger subscript values compare greater than pointers to elements of the same array with lower subscript values. [...]
Thus &array[x] >= &array[0] is true always if x is the index of an element, or one greater than the maximum index. (And if x is not the index of an element, or one past the end of the actual array, then behaviour is undefined.)
But surprisingly the difference &array[x] - &array[0] is defined only when
x is an actual index of an element or one greater than the maximum index in the array and
x is not greater than PTRDIFF_MAX
as there is a peculiar corner case: C11 6.5.6p9 says that
9 When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object; the result is the difference of the subscripts of the two array elements. The size of the result is implementation-defined, and its type (a signed integer type) is ptrdiff_t defined in the <stddef.h> header. If the result is not representable in an object of that type, the behavior is undefined. In other words, if the expressions P and Q point to, respectively, the i-th and j-th elements of an array object, the expression (P)-(Q) has the value i-j provided the value fits in an object of type ptrdiff_t.[...]
If the signed ptrdiff_t is of same width as the unsigned size_t, it is possible to have an array for which there exists an index x greater than PTRDIFF_MAX; then &array[x] >= &array[0] still, but &array[x] - &array[0] has completely undefined behaviour.
Here is a demonstration. My computer is x86-64 that runs 64-bit Ubuntu Linux, but it is also capable of running 32-bit programs. In 32-bit X86 Linux + GCC, ptrdiff_t is a 32-bit signed integer, and size_t is 32-bit unsigned integer. A program run in 64-bit Linux in 32-bit mode can easily allocate over 2G of memory with malloc, as the entire 4G address space is reserved for user mode.
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <stddef.h>
int main(void) {
size_t size = (size_t)PTRDIFF_MAX + 2;
size_t x = (size_t)PTRDIFF_MAX + 1;
char *array = malloc(size);
if (! array) {
perror("malloc");
exit(1);
}
array[0] = 42;
array[x] = 84;
printf("&array[0]: %p\n", (void *)&array[0]);
printf("&array[x]: %p\n", (void *)&array[x]);
printf("&array[x] >= &array[0]: %d\n", &array[x] >= &array[0]);
printf("&array[x] - &array[1]: %td\n", &array[x] - &array[1]);
printf("&array[x] - &array[0]: %td\n", &array[x] - &array[0]);
printf("(&array[x] - &array[0]) < 0: %d\n", (&array[x] - &array[0]) < 0);
}
Then compiled for 32-bit mode and run:
% gcc huge.c -m32 -Wall && ./a.out
&array[0]: 0x77567008
&array[x]: 0xf7567008
&array[x] >= &array[0]: 1
&array[x] - &array[1]: 2147483647
&array[x] - &array[0]: -2147483648
(&array[x] - &array[0]) < 0: 1
The memory was allocated successfully, the starting address is at 0x77558008, &array[x] is at 0xf7504008, &array[x] is greater than &array[0]. The difference &array[x] - &array[1] produced a positive result, whereas &array[x] - &array[0], with its undefined behaviour, now produced a negative result!
First of all, FWIW, quoting C11, chapter §6.5.6/P9, (emphsis mine)
When two pointers are subtracted, both shall point to elements of the same array object,
or one past the last element of the array object; the result is the difference of the
subscripts of the two array elements. [...]
So, you don't need to be bothered about the individual pointer value (positioning) itself. It's the difference that matters (i.e, something like |a-b|)
That said, if it has to come to the "comparison", ( usage of relational operators, <, >, <=, >=), the standard says,
When two pointers are compared, the result depends on the relative locations in the
address space of the objects pointed to. [....] If the objects pointed to are members of the same aggregate object, [...] and pointers to array elements with larger subscript
values compare greater than pointers to elements of the same array with lower subscript values. [....]
So, for a statement like &array[x] <= &array[0], it will evaluate to 0 (FALSY), when x > 0.
Thanks to the other answer by Joachim
Yes, because &array[x] is defined to be equivalent to array+x.
6.5.2.1p2:
A postfix expression followed by an expression in square brackets []
is a subscripted designation of an element of an array object. The
definition of the subscript operator [] is that E1[E2] is identical to
(*((E1)+(E2))). Because of the conversion rules that apply to the
binary + operator, if E1 is an array object (equivalently, a pointer
to the initial element of an array object) and E2 is an integer,
E1[E2] designates the E2-th element of E1 (counting from zero).
The C11 standard defines the address difference between elements of an array as a number that depends on the relative (logical) order of the elements. As specified in the description of the additive operators:
When two pointers are subtracted, both shall point to elements of the
same array object, or one past the last element of the array object;
the result is the difference of the subscripts of the two array
elements. The size of the result is implementation-defined, and its
type (a signed integer type) is ptrdiff_t defined in the
header. If the result is not representable in an object of that type,
the behavior is undefined. In other words, if the expressions P and Q
point to, respectively, the i-th and j-th elements of an array object,
the expression (P)-(Q) has the value i-j provided the value fits in an
object of type ptrdiff_t. Moreover, if the expression P points either
to an element of an array object or one past the last element of an
array object, and the expression Q points to the last element of the
same array object, the expression ((Q)+1)-(P) has the same value as
((Q)-(P))+1 and as -((P)-((Q)+1)), and has the value zero if the
expression P points one past the last element of the array object,
even though the expression (Q)+1 does not point to an element of the
array object.
So the difference in your example is defined as x - 0.
From the C11 specification (ISO/IEC 9899:2011 (E)) §6.5.8/5:
When two pointers are compared, ... If the objects pointed to are members of the same aggregate object, ... and pointers to array elements with larger subscript values compare greater than pointers to elements of the same array with lower subscript values.
That means that &array[x] <= &array[0] will be false unless x is equal to zero.
Given that traversing a array can also be achieve by incrementing a pointer, it would appear to be fairly fundamental that the absolute address of subsequent indexes increase.
char[] foobar;
char *foobarPtr = foobar;
foobar[0] == *foobarPtr++;
foobar[1] == *foobarPtr++;
https://www.tutorialspoint.com/cprogramming/c_pointer_to_an_array.htm
index = &array[x] - &array[0];
is syntactic sugar for
index = (array+x) - (array+0)
because in C any array is desugared as pointer.
Now given the pointer arithmetic it will be rewritten as index = x
The relevant topics you can google for or search inside ISO9899 are pointer arithmetic and desugaring arrays as pointers.

One-dimensional access to a multidimensional array: is it well-defined behaviour?

I imagine we all agree that it is considered idiomatic C to access a true multidimensional array by dereferencing a (possibly offset) pointer to its first element in a one-dimensional fashion, e.g.:
void clearBottomRightElement(int *array, int M, int N)
{
array[M*N-1] = 0; // Pretend the array is one-dimensional
}
int mtx[5][3];
...
clearBottomRightElement(&mtx[0][0], 5, 3);
However, the language-lawyer in me needs convincing that this is actually well-defined C! In particular:
Does the standard guarantee that the compiler won't put padding in-between e.g. mtx[0][2] and mtx[1][0]?
Normally, indexing off the end of an array (other than one-past the end) is undefined (C99, 6.5.6/8). So the following is clearly undefined:
struct {
int row[3]; // The object in question is an int[3]
int other[10];
} foo;
int *p = &foo.row[7]; // ERROR: A crude attempt to get &foo.other[4];
So by the same rule, one would expect the following to be undefined:
int mtx[5][3];
int (*row)[3] = &mtx[0]; // The object in question is still an int[3]
int *p = &(*row)[7]; // Why is this any better?
So why should this be defined?
int mtx[5][3];
int *p = &(&mtx[0][0])[7];
So what part of the C standard explicitly permits this? (Let's assume c99 for the sake of discussion.)
EDIT
Note that I have no doubt that this works fine in all compilers. What I'm querying is whether this is explicitly permitted by the standard.
All arrays (including multidimensional ones) are padding-free. Even if it's never explicitly mentioned, it can be inferred from sizeof rules.
Now, array subscription is a special case of pointer arithmetics, and C99 section 6.5.6, §8 states clearly that behaviour is only defined if the pointer operand and the resulting pointer lie in the same array (or one element past), which makes bounds-checking implementations of the C language possible.
This means that your example is, in fact, undefined behaviour. However, as most C implementations do not check bounds, it will work as expected - most compilers treat undefined pointer expressions like
mtx[0] + 5
identically to well-defined counterparts like
(int *)((char *)mtx + 5 * sizeof (int))
which is well-defined because any object (including the whole two-dimensional array) can always be treated as a one-dimensinal array of type char.
On further meditation on the wording of section 6.5.6, splitting out-of-bounds access into seemingly well-defined subexpression like
(mtx[0] + 3) + 2
reasoning that mtx[0] + 3 is a pointer to one element past the end of mtx[0] (making the first addition well-defined) and as well as a pointer to the first element of mtx[1] (making the second addition well-defined) is incorrect:
Even though mtx[0] + 3 and mtx[1] + 0 are guaranteed to compare equal (see section 6.5.9, §6), they are semantically different. For example, the former can't be dereferenced and thus does not point to an element of mtx[1].
The only obstacle to the kind of access you want to do is that objects of type int [5][3] and int [15] are not allowed to alias one another. Thus if the compiler is aware that a pointer of type int * points into one of the int [3] arrays of the former, it could impose array bounds restrictions that would prevent accessing anything outside that int [3] array.
You might be able to get around this issue by putting everything inside a union that contains both the int [5][3] array and the int [15] array, but I'm really unclear on whether the union hacks people use for type-punning are actually well-defined. This case might be slightly less problematic since you would not be type-punning individual cells, only the array logic, but I'm still not sure.
One special case that should be noted: if your type were unsigned char (or any char type), accessing the multi-dimensional array as a one-dimensional array would be perfectly well-defined. This is because the one-dimensional array of unsigned char that overlaps it is explicitly defined by the standard as the "representation" of the object, and is inherently allowed to alias it.
It is sure that there is no padding between the elements of an array.
There are provision for doing address computation in smaller size than the full address space. This could be used for instance in the huge mode of 8086 so that the segment part would not always be updated if the compiler knew that you couldn't cross a segment boundary. (It's too long ago for me to remind if the compilers I used took benefit of that or not).
With my internal model -- I'm not sure it is perfectly the same as the standard one and it is too painful to check, the information being distributed everywhere --
what you are doing in clearBottomRightElement is valid.
int *p = &foo.row[7]; is undefined
int i = mtx[0][5]; is undefined
int *p = &row[7]; doesn't compile (gcc agree with me)
int *p = &(&mtx[0][0])[7]; is in the gray zone (last time I checked in details something like this, I ended up by considering invalid C90 and valid C99, it could be the case here or I could have missed something).
My understanding of the C99 standard is that there is no requirement that multidimensional arrays must be laid out in a contiguous order in memory. Following the only relevant information I found in the standard (each dimension is guaranteed to be contiguous).
If you want to use the x[COLS*r + c] access, I suggest you stick to single dimension arrays.
Array subscripting
Successive subscript operators designate an element of a multidimensional array object.
If E is an n-dimensional array (n ≥ 2) with dimensions i × j × . . . × k, then E (used as
other than an lvalue) is converted to a pointer to an (n − 1)-dimensional array with
dimensions j × . . . × k. If the unary * operator is applied to this pointer explicitly, or
implicitly as a result of subscripting, the result is the pointed-to (n − 1)-dimensional array,
which itself is converted into a pointer if used as other than an lvalue. It follows from this
that arrays are stored in row-major order (last subscript varies fastest).
Array type
— An array type describes a contiguously allocated nonempty set of objects with a
particular member object type, called the element type.
36)
Array types are
characterized by their element type and by the number of elements in the array. An
array type is said to be derived from its element type, and if its element type is T , the
array type is sometimes called ‘‘array of T ’’. The construction of an array type from
an element type is called ‘‘array type derivation’’.

Resources