<prune>
Playing word games can work both ways, example:
int x;
The actual integer object is just a a piece of memory, x is just an
identifier. So are we wrong to say x is an integer? Likewise:
int* arr = new int[16];
The actual array object is just a piece of memory, arr is just an
identifier. So are we wrong to say arr is an array?
int x; /* x is an integer */
int * p = &x; /* p is a pointer to an integer */
int a[3]; /* a is an array of 3 integers */
int * pa = a; /* pa is a pointer to an integer */
int * dx = new int(); /* dx is a pointer to an integer */
int * da = new int[3]; /* da is a pointer to an integer */
Because 'pa' and 'da' both point to the first element of an array, it is
well defined to do pointer arithmatic on them as long as you stay within
the bounds of the underlying array (e.g 'pa[1]' which is equivalent to
'*(pa + 1)'). With 'a', 'a[1]' is again equivalent '*(a + 1)'. However,
since a is actually an array, a is implicitly converted to type int*
before operator+ can be applied, so it is equivalent to '*((int*)a + 1)'.
Basically what you are saying is that... yes it's well defined to create an
non zero based array in C++. ?
Look at this :
int* arr = new arr[16];
++arr;
arr[-1] = 10;
int * arr; /* arr has type 'int *' (eg pointer to int) */
arr = new int[16]; /* arr points to the first element of an array */
++arr; /* arr points to the second element of the array */
arr[-1] = 10; /* same as *(arr - 1) */
The important thing to note here is that arr does not suddenly become an
array when we assign 'new int[16]' to it. It remains a pointer only (eg.
I
could assign the address of a normal integer to it. This would not be
smart without saving the origional value, but nonetheless can be done).
I have not (and I don't think anyone else has) said that the argument to
operator[] (E2) must be nonnegative, only that it must stay within the
bounds of the underlying array object. What we have said is that if E1
*is
an array* then it is undefined behavior if you use a negative index.
(For
if E1 is an array (not a pointer), any negative value will be out of
bounds (and therefore undefined behavior.))
Yes what you are saying is that with a static array declared like so:
int arr[16];
...cannot have a negative array index because these arrays are always
zero-based. I agree(within the bounds of standard C++)
Good.
But I disagree with you saying E1 is not an array like so:
int* E1 = new int[16];
++E1;
E1[-1]= 6;
In the expression E1[-1].... E1 is used as an array. The name "E1" is the
name for both the pointer and the array.
E1 is of type 'int *' (a pointer). The expression 'new int[16]'
dynamically
creates an (unnamed) array and return a pointer to the first element.
When
this element is assigned to E1, E1 does not suddenly become an array
(it
remains a pointer). The name "E1" identifies only the pointer. The
array
has no name.
The expression '++E1;' changes the value of the pointer (the address
that it
points to). It is equivalent to the pointer arithmetic 'E1 = E1 + 1;'.
In the expression 'E1[-1] = 6;', E1 is used as a pointer (as that is
what it is).
It is equivalent to '*(E1 - 1) = 6;'. This means that the compiler
subtracts 1
from the pointer, and then dereferences the new pointer value, and
assigns 6 to
whatever is pointed to (which happens to be the first element of an
array.
int arr[16];
arr[2] = 6;
In the expression 'arr[2] = 6;', arr is used as a pointer. This is
equivalent to
'*(arr + 2)', but as operator+ is not defined for arrays but is for
pointers, and
an array can be converted to a pointer to it's first element, it is
further
transformed to '*((int *)arr + 2)'. (ie. arr is first converted to a
pointer, and
then pointer arithmetic is done on the result).
That is why the standard says that *because of the conversion rules
defined for
operator+*, if E1 *is an array* E1[E2] refers to the E2th element of
E1. ie.
because (int *)E1 returns a pointer referring to the first (1-based)
element of E1,
doing pointer arithmetic on this value with a (positive) integer (less
than the
length of the array) E2 is well defined behavior and refers to the
E2th (0-based)
(or (E2 + 1)th (1-based) if you prefer thinking that way) element of
E1.
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
I am not even reading your long winded explnation of what E1 is above.
I'm simply "telling" you it's an array, I don't care what you think I'm
telling you wehat it simply is.
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
The text from the standard seems to have been written to explain the
behaviour of both dynamic and static arrays. Please don't try to interpret
it to mean something along the lines of ..E1 is an array and not a
pointer.
The standard also states someplace that array indexing with static arrays
is identical to using pointers, so its intended meaning is obvious.
int arr[4];
arr[1] = 6;
int * ptr = arr;
ptr[1] = 6;
Yes, the standard states that 'arr[1]' is the same as 'int * ptr =
arr; ptr[1]'.
Yes, this explains the behavior of both static and dynamic arrays (see
below).
No, this does not mean that a pointer to an element of an array (even
to the first
element) is itself an array. It remains a pointer.
The name/identifier in the expression arr[-1] is the name of both a pointer
and an array. The expression is converted to *((arr)+(-1)).
That is, in the context of E1[E2], E2 is the -1th member of arr.
Normal people would probably prefer to think that -1, in this case, refers
to the 1st element.
This is the only reasonable way to interpret array indexing as defined in
the C++ standard. To suggest that array indices can never be negative just
seems like a foolish misconception through misintepretations of the
standards.
The following code is well-defined. There are two integers (one static
and one dynamic), two integer arrays of length 16 (one static and one
dynamic), and four pointers to integers (all static).
Even though the integer and integer array defined statically have
names
('i' and 'ptr' respectively) they are not known in main.cpp, and we
can
only refer to them indirectly through their address (returned by the
functions 'get_integer()' and 'get_array()'). The dynamic objects do
not
have names of there own, so we can only refer to them indirectly
through
their addresses (returned by 'new int()' and 'new int[16]').
The expressions 'ptrn[0]' (with n being one of 1, 2, 3, or 4) are
transformed into '*(ptrn + 0)' which is the same as *ptrn. I hope that
you can see that ptr1 and ptr2 are no more arrays than ptr3 and ptr4
are even though they all are used as operands to operator[].
/* foo.h */
int * get_array();
int * get_integer();
/* foo.cpp */
int arr[16];
int i;
int * get_array() {
return arr;
/* returns the address of the first element of an array */
}
int * get_integer() {
return &i;
/* returns the address of an integer */
}
/* main.cpp */
int main() {
int * ptr1, * ptr2, * ptr3, * ptr4;
ptr1 = get_array();
ptr2 = new int[16];
ptr3 = get_integer();
ptr4 = new int();
ptr1[0] = 10;
ptr2[0] = 10;
ptr3[0] = 10;
ptr4[0] = 10;
}