Array indexing

J

Joshua Neuheisel

The following code compiles with gcc 3.2.2 and Visual C++ 6:

#include <stdio.h>
int main()
{
int a[2] = {3, 4};
printf ("%d\n", 0[a]);
return 0;
}

The unusual part is the "0[a]". The compilers translate this to
"a[0]" with no warning. Has anyone else seen this behavior, or better
yet, can anyone explain it? It seems like "index[array]" is
equivalent to "array[index]".
 
B

Ben Pfaff

The unusual part is the "0[a]". The compilers translate this to
"a[0]" with no warning.

This is in the FAQ.

6.11: I came across some "joke" code containing the "expression"
5["abcdef"] . How can this be legal C?

A: Yes, Virginia, array subscripting is commutative in C. This
curious fact follows from the pointer definition of array
subscripting, namely that a[e] is identical to *((a)+(e)), for
*any* two expressions a and e, as long as one of them is a
pointer expression and one is integral. This unsuspected
commutativity is often mentioned in C texts as if it were
something to be proud of, but it finds no useful application
outside of the Obfuscated C Contest (see question 20.36).

References: Rationale Sec. 3.3.2.1; H&S Sec. 5.4.1 p. 124,
Sec. 7.4.1 pp. 186-7.
 
J

Joona I Palaste

Joshua Neuheisel said:
The following code compiles with gcc 3.2.2 and Visual C++ 6:
#include <stdio.h>
int main()
{
int a[2] = {3, 4};
printf ("%d\n", 0[a]);
return 0;
}
The unusual part is the "0[a]". The compilers translate this to
"a[0]" with no warning. Has anyone else seen this behavior, or better
yet, can anyone explain it? It seems like "index[array]" is
equivalent to "array[index]".

Yes, it certainly is. What's more, any expression such as "a" is
equivalent to "b[a]" if exactly one of a, b is a pointer and the other
is a scalar integer.
This is a deliberate feature of C, and is completely standard, portable,
and safe. It's due to the fact that a gets internally translated to
*(a+b), and + is commutative.

--
/-- Joona Palaste ([email protected]) ---------------------------\
| Kingpriest of "The Flying Lemon Tree" G++ FR FW+ M- #108 D+ ADA N+++|
| http://www.helsinki.fi/~palaste W++ B OP+ |
\----------------------------------------- Finland rules! ------------/
"Remember: There are only three kinds of people - those who can count and those
who can't."
- Vampyra
 
T

Tom St Denis

Joshua said:
The following code compiles with gcc 3.2.2 and Visual C++ 6:

#include <stdio.h>
int main()
{
int a[2] = {3, 4};
printf ("%d\n", 0[a]);
return 0;
}

The unusual part is the "0[a]". The compilers translate this to
"a[0]" with no warning. Has anyone else seen this behavior, or better
yet, can anyone explain it? It seems like "index[array]" is
equivalent to "array[index]".

That actually makes sense.

Say &a[0] is 0x30000000

Then (int)a == 0x30000000 is valid.

Then 0[a] simply means *(&0 + a) which is *(0 + 0x30000000) == *(0x30000000)

Assuming that is what happened. And no, index[array] != array[index]
since index[array] will not multiply index by the sizeof array[0].

Tom
 
T

Tom St Denis

Tom said:
Assuming that is what happened. And no, index[array] != array[index]
since index[array] will not multiply index by the sizeof array[0].

Oops, it does.

Oh well.

Tom
 
C

Christian Bau

Tom St Denis said:
Joshua said:
The following code compiles with gcc 3.2.2 and Visual C++ 6:

#include <stdio.h>
int main()
{
int a[2] = {3, 4};
printf ("%d\n", 0[a]);
return 0;
}

The unusual part is the "0[a]". The compilers translate this to
"a[0]" with no warning. Has anyone else seen this behavior, or better
yet, can anyone explain it? It seems like "index[array]" is
equivalent to "array[index]".

That actually makes sense.

Say &a[0] is 0x30000000

Then (int)a == 0x30000000 is valid.

Then 0[a] simply means *(&0 + a) which is *(0 + 0x30000000) == *(0x30000000)

Assuming that is what happened. And no, index[array] != array[index]
since index[array] will not multiply index by the sizeof array[0].

Tom, will you please get your copy of the C Standard out, read the
definition of the [] operator, think about it, and then post a
correction?
 
K

Keith Thompson

Ben Pfaff said:
6.11: I came across some "joke" code containing the "expression"
5["abcdef"] . How can this be legal C?

A: Yes, Virginia, array subscripting is commutative in C. This
curious fact follows from the pointer definition of array
subscripting, namely that a[e] is identical to *((a)+(e)), for
*any* two expressions a and e, as long as one of them is a
pointer expression and one is integral. This unsuspected
commutativity is often mentioned in C texts as if it were
something to be proud of, but it finds no useful application
outside of the Obfuscated C Contest (see question 20.36).

References: Rationale Sec. 3.3.2.1; H&S Sec. 5.4.1 p. 124,
Sec. 7.4.1 pp. 186-7.

Array subscripting is commutative because addition is commutative.

In most uses of the addition operator, the left and right operands are
of the same type. The exception to this is pointer arithmetic; you
can't sensibly add two pointers, but you can add a pointer and an
integer, yielding a pointer as the result. Both "pointer + integer"
and "integer + pointer" are legal and have the same meaning.

In my opinion, it would have been no loss to the language if the
pointer were required to be the left operand. Certainly there would
be no loss of expressive power. As a side effect of such a change,
array[index] would remain legal, but index[array] would become
illegal.

If you were to think of the various forms of "+" as overloaded
operators, declared with some function-like syntax, the
pointer+integer and integer+pointer forms would have to be declared as
two separate functions. Of course, C doesn't declare its operators
that way; the point is that allowing both forms adds to the
complexity.

I'm not advocating such a change now; the bureaucratic overhead would
exceed any benefit. But it's one of the many things that I would do
differently if I were designing a C-like language from scratch. (In
the process, of course, I would commit new and original design errors
that K&R never dreamed of.)
 
P

pete

Keith Thompson wrote:
In my opinion, it would have been no loss to the language if the
pointer were required to be the left operand. Certainly there would
be no loss of expressive power. As a side effect of such a change,
array[index] would remain legal, but index[array] would become
illegal.

If you were to think of the various forms of "+" as overloaded
operators, declared with some function-like syntax, the
pointer+integer and integer+pointer forms would have to be declared as
two separate functions. Of course, C doesn't declare its operators
that way; the point is that allowing both forms adds to the
complexity.

I'm not advocating such a change now; the bureaucratic overhead would
exceed any benefit.
But it's one of the many things that I would do
differently if I were designing a C-like language from scratch. (In
the process, of course, I would commit new and original design errors
that K&R never dreamed of.)

Your opinion is missing the part which explains why you
want index[array] to be illegal.
What benefit?
 
K

Keith Thompson

pete said:
Keith Thompson wrote: [...]
I'm not advocating such a change now; the bureaucratic overhead would
exceed any benefit.
But it's one of the many things that I would do
differently if I were designing a C-like language from scratch. (In
the process, of course, I would commit new and original design errors
that K&R never dreamed of.)

Your opinion is missing the part which explains why you
want index[array] to be illegal.
What benefit?

What's the benefit of making such a counterintuitive construct legal?
As the C FAQ says, "This unsuspected commutativity is often mentioned
in C texts as if it were something to be proud of, but it finds no
useful application outside of the Obfuscated C Contest".

As I said, I'm not advocating making such a change, merely regretting
(mildly) that the feature was put into the language in the first
place.

If compatibility were not an issue, would you really want both
array[index] and index[array] to be valid? If so, why?
 
P

pete

Keith said:
If compatibility were not an issue, would you really want both
array[index] and index[array] to be valid? If so, why?

If by *really*, you're asking if I think it's important
that I should be able to write code with index[array],
I'd say, "No, not really".

But, one of the things that I like about both the K&R books
and the C89 standard, is that compared to other books and standards,
they're small. Making that particular construct illegal,
would just be another rule to learn.

If you know the rules about pointers,
but the only thing that you know about the array subscript operator
is that index[array], means *(index + array),
then you know or can construe
everything that there is to know about the array subscript operator.
 
K

Keith Thompson

pete said:
Keith said:
If compatibility were not an issue, would you really want both
array[index] and index[array] to be valid? If so, why?

If by *really*, you're asking if I think it's important
that I should be able to write code with index[array],
I'd say, "No, not really".

But, one of the things that I like about both the K&R books
and the C89 standard, is that compared to other books and standards,
they're small. Making that particular construct illegal,
would just be another rule to learn.

If you know the rules about pointers,
but the only thing that you know about the array subscript operator
is that index[array], means *(index + array),
then you know or can construe
everything that there is to know about the array subscript operator.

I see your point, but I disagree.

I see "pointer + integer yields pointer" and "integer + pointer yields
pointer" as two different rules. If the left and right operands are
of vastly different types, I see no great virtue in commutativity. I
would have preferred "pointer + integer yields pointer" and "integer
plus pointer is illegal". Aside from reducing complexity and
eliminating the useless obfuscation of index[array], this would also
more closely parallel the rules for pointer subtraction: "pointer -
integer yields pointer" and "integer - pointer is illegal". (The
analogy is weakened by the existence of "pointer - pointer yields
integer"; oh, well.)

This overloading of the "+" operator is built into the language.
Languages that allow programmers to define their own operator
overloading typically use something that looks like (or is) a function
definition. The ones I'm familiar with don't automatically force
user-defined "+" to be commutative. For example, in Ada, a
declaration like
function "+"(Left: Ptr; Right: Integer) return Ptr;
would not imply a declaration like
function "+"(Left: Integer; Right: Ptr) return Ptr;
If you want both, you have to declare both. (Replace function "+"
with operator+ and turn the syntax inside out for C++.)

On the other hand, if you think of commutativity as being at the very
core of what addition is all about, it certainly makes sense for
"pointer + integer" and "integer + pointer" to mean the same thing --
but then you'd have trouble with some languages' use of an overloaded
"+" operator to denote string catenation.

In any case, backward compatibility trumps both our arguments, so you
win. :cool:}
 
P

pete

Keith said:
pete said:
Keith said:
If compatibility were not an issue, would you really want both
array[index] and index[array] to be valid? If so, why?

If by *really*, you're asking if I think it's important
that I should be able to write code with index[array],
I'd say, "No, not really".

But, one of the things that I like about both the K&R books
and the C89 standard, is that compared to other books and standards,
they're small. Making that particular construct illegal,
would just be another rule to learn.

If you know the rules about pointers,
but the only thing that you know about the array subscript operator
is that index[array], means *(index + array),
then you know or can construe
everything that there is to know about the array subscript operator.

I see your point, but I disagree.

I see "pointer + integer yields pointer" and "integer + pointer yields
pointer" as two different rules. If the left and right operands are
of vastly different types, I see no great virtue in commutativity. I
would have preferred "pointer + integer yields pointer" and "integer
plus pointer is illegal". Aside from reducing complexity and
eliminating the useless obfuscation of index[array], this would also
more closely parallel the rules for pointer subtraction: "pointer -
integer yields pointer" and "integer - pointer is illegal". (The
analogy is weakened by the existence of "pointer - pointer yields
integer"; oh, well.)

Sometimes you can get a simpler looking expression by
putting the integer first.
You can write
(size_1 - size_2 + array)
when (size_1) exceeds the size of the array,
and (size_1 - size_2) doesn't.

But if you want pointer first, then you have to use parentheses:
(array + (size_1 - size_2))
 
K

Keith Thompson

pete said:
Sometimes you can get a simpler looking expression by
putting the integer first.
You can write
(size_1 - size_2 + array)
when (size_1) exceeds the size of the array,
and (size_1 - size_2) doesn't.

But if you want pointer first, then you have to use parentheses:
(array + (size_1 - size_2))

Hmm. Maybe it's just me, but the only way I can make sense of
(size_1 - size_2 + array) is by mentally transforming it to
(array + (size_1 - size_2)).

I think I store pointers in the left side of my brain and integers in
the right side of my brain. (Don't ask me where I store
floating-point values.)
 
C

Chris Dollin

Keith said:
I think I store pointers in the left side of my brain and integers in
the right side of my brain. (Don't ask me where I store
floating-point values.)

Presumably, they float around the pointers.
 
P

Peter Shaggy Haywood

Groovy hepcat Keith Thompson was jivin' on Wed, 16 Jul 2003 00:33:38
GMT in comp.lang.c.
Re: Array indexing's a cool scene! Dig it!
pete said:
Keith said:
If compatibility were not an issue, would you really want both
array[index] and index[array] to be valid? If so, why?

If by *really*, you're asking if I think it's important
that I should be able to write code with index[array],
I'd say, "No, not really".

But, one of the things that I like about both the K&R books
and the C89 standard, is that compared to other books and standards,
they're small. Making that particular construct illegal,
would just be another rule to learn.

If you know the rules about pointers,
but the only thing that you know about the array subscript operator
is that index[array], means *(index + array),
then you know or can construe
everything that there is to know about the array subscript operator.

I see your point, but I disagree.

I see "pointer + integer yields pointer" and "integer + pointer yields
pointer" as two different rules. If the left and right operands are

But they're not two different rules. A + B has always been equal to
B + A, and not just in C, but in mathematics and in real life.
If I hold a pencil in my right hand and an apple in my left hand,
I'm holding an apple and a pencil. OTOH, if I hold an apple in my
right hand and a pencil in my left, I'm holding an apple and a pencil.
It doesn't matter that the apple and the pencil are two completely
different types of objects; when they're added to gether, it doesn't
matter which is on the right and which is on the left; they're still
an apple and a pencil. So it is with pointer addition in C.
of vastly different types, I see no great virtue in commutativity. I
would have preferred "pointer + integer yields pointer" and "integer
plus pointer is illegal". Aside from reducing complexity and

How would that reduce complexity? It may increase complexity
eliminating the useless obfuscation of index[array], this would also
more closely parallel the rules for pointer subtraction: "pointer -
integer yields pointer" and "integer - pointer is illegal". (The

Subtraction is not commutative; not just with pointers and integers,
but any types (even the same type). (A - B) != (B - A) except when B
== A, no matter what their type(s).
Integer - pointer just doesn't make sense. Integer + pointer does,
however.
analogy is weakened by the existence of "pointer - pointer yields
integer"; oh, well.)

If pointer + integer yields pointer, then it makes perfect sense
that pointer - pointer yields integer (and that pointer - integer
yields pointer).
This overloading of the "+" operator is built into the language.
Languages that allow programmers to define their own operator
overloading typically use something that looks like (or is) a function
definition. The ones I'm familiar with don't automatically force
user-defined "+" to be commutative. For example, in Ada, a
declaration like
function "+"(Left: Ptr; Right: Integer) return Ptr;
would not imply a declaration like
function "+"(Left: Integer; Right: Ptr) return Ptr;
If you want both, you have to declare both. (Replace function "+"
with operator+ and turn the syntax inside out for C++.)

These are not really addition operators. They are a type of function
designed to do whatever the programmer writes them to do (within the
possibilities of the language, of course).
On the other hand, if you think of commutativity as being at the very
core of what addition is all about, it certainly makes sense for
"pointer + integer" and "integer + pointer" to mean the same thing --

Right. (We are talking about the inherent functionality of addition,
which is commutative in nature, not the "+" character.)
but then you'd have trouble with some languages' use of an overloaded
"+" operator to denote string catenation.

That's not addition, but concatenation. It uses the "+" character to
represent it, but it's not the same thing. It doesn't belong in this
discussion.
In any case, backward compatibility trumps both our arguments, so you
win. :cool:}

Common sense has alot to do with it too.

--

Dig the even newer still, yet more improved, sig!

http://alphalink.com.au/~phaywood/
"Ain't I'm a dog?" - Ronny Self, Ain't I'm a Dog, written by G. Sherry & W. Walker.
I know it's not "technically correct" English; but since when was rock & roll "technically correct"?
 
K

Keith Thompson

Groovy hepcat Keith Thompson was jivin' on Wed, 16 Jul 2003 00:33:38
GMT in comp.lang.c.
Re: Array indexing's a cool scene! Dig it! [...]
If I hold a pencil in my right hand and an apple in my left hand,
I'm holding an apple and a pencil. OTOH, if I hold an apple in my
right hand and a pencil in my left, I'm holding an apple and a pencil.
It doesn't matter that the apple and the pencil are two completely
different types of objects; when they're added to gether, it doesn't
matter which is on the right and which is on the left; they're still
an apple and a pencil.

I think the apple/pencil analogy supports my position better than
yours. It can matter a great deal whether the pencil is in my left
hand or in my right hand. If I hold a pencil in my right hand,
there's some chance you'll be able to read what I write with it.

But of course that's a statement about your analogy, not about your
underlying argument.
So it is with pointer addition in C.

In C as it's currently defined, yes (and I'm not advocating a change).

[...]
If pointer + integer yields pointer, then it makes perfect sense
that pointer - pointer yields integer (and that pointer - integer
yields pointer).

I agree completely.
These are not really addition operators. They are a type of function
designed to do whatever the programmer writes them to do (within the
possibilities of the language, of course).

The distinction between operators and functions is largely artificial.
In some languages, it's practically nonexistent.
Right. (We are talking about the inherent functionality of addition,
which is commutative in nature, not the "+" character.)

Ok, so you think of addition as being *fundamentally* commutative. I
don't.

Computer science obviously borrowed the concept of addition from
mathematics. In both pure mathematics and programming, addition
(i.e., expressions of the form X + Y) is commonly overloaded, meaning
that the operands can be of a number of different types. In pure
mathematics, the operands can be integers, real numbers, rational
numbers, complex numbers, quaternions, vectors, matrices, etc. In
most programming languages, the operands can be integers (signed or
unsigned, various sizes), floating-point numbers (often of various
sizes), and sometimes complex numbers and various other
language-specific things.

Something that I've rarely seen in mathematics is an addition operator
whose operands are of different types. I suppose you could add a
point and a vector, yielding a point, but I don't recall that kind of
thing being referred to as an addition operation.

[...]
Common sense has alot to do with it too.

Well, my common sense apparently differs a bit from yours. That's not
necessarily a bad thing.

(Some people's common sense might say that multiplication is always
commutative, but in mathematics it often isn't.)
 
G

Glen Herrmannsfeldt

message
(snip)
Subtraction is not commutative; not just with pointers and integers,
but any types (even the same type). (A - B) != (B - A) except when B
== A, no matter what their type(s).
Integer - pointer just doesn't make sense. Integer + pointer does,
however.


If pointer + integer yields pointer, then it makes perfect sense
that pointer - pointer yields integer (and that pointer - integer
yields pointer).

The IBM OS/360 assembler allows the equivalent of integer-pointer, or
pointer+pointer. That is, address constants can have relocation factors
of -1, 0, 1, or 2. It isn't all that hard to do, though for C it would
require two extra data attributes.

Consider the following.

int i,j,*p,*q,*r;

The expressions p-q+r, or p+r-q are legal,

The expressions p+r-q, -q+p+r, i-q+p, or (i-q)+(p+j) are not, yet all these
mathematically yield a pointer or integer value.

It isn't especially obvious that p+r-q should be illegal while p-q+r is
legal, any more than the commutativity of pointer and integer addition.

Note that I am not arguing against the commutativity of pointer+integer.

-- glen
 
K

Kevin Easton

Keith Thompson said:
Something that I've rarely seen in mathematics is an addition operator
whose operands are of different types. I suppose you could add a
point and a vector, yielding a point, but I don't recall that kind of
thing being referred to as an addition operation.

If you think of it as "position + displacement = position", then it's
quite common - in physics, anyway. This is quite a strong analogy with
"pointer + integer = pointer" actually, if you think about it - in C,
pointers are effectively positions within arrays, and the integer is
being treated as a displacement between two array positions.

- Kevin.
 

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

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,534
Members
45,007
Latest member
OrderFitnessKetoCapsules

Latest Threads

Top