15

Possible Duplicate:
In C arrays why is this true? a[5] == 5[a]

Is the possibility of both array[index] and index[array] a compiler feature or a language feature. How is the second one possible?

1

4 Answers 4

30

The compiler will turn

index[array]

into

*(index + array)

With the normal syntax it would turn

array[index]

into

*(array + index)

and thus you see that both expressions evaluate to the same value. This holds for both C and C++.

Sign up to request clarification or add additional context in comments.

2 Comments

This 'transformation' illustration only holds when one of the variables is a pointer or an array and the other is an integer type, i.e. the usual C case. In C++, a[b] loses its symmetry as operator[] can be an overloaded member function and the compiler is not allowed to use *(a+b) instead. *(a+b) might have a different type and a different value or it might not be a valid expression at all.
+1. Cool. Never thought of it that way.
6

From the earliest days of C, the expression a[i] was simply the address of a[0] added to i (scaled up by the size of a[0]) and then de-referenced. In fact, all these were equivalent:

a[i]
i[a]
*(a+i)

====

The only thing I'd be concerned about is the actual de-referencing. Whilst they all produce the same address, de-referencing may be a concern if the types of a and i are different.

For example:

    int i = 4;
    long a[9];
    long x = a[i]; //get the long at memory location X.
    long x = i[a]; //get the int at memory location X?

I haven't actually tested that behavior but it's something you may want to watch out for. If it does change what gets de-referenced, it's likely to cause all sorts of problems with arrays of objects as well.

====

Update:

You can probably safely ignore the bit above between the ===== lines. I've tested it under Cygwin with a short and a long and it seems okay, so I guess my fears were unfounded, at least for the basic cases. I still have no idea what happens with more complicated ones because it's not something I'm ever likely to want to do.

5 Comments

I don't think it is different. I meant it dates from the earliest days, not that it was only like that in the early days.
This is wrong. Either way, the compiler knows adding an int to a long* (in either order) results in a long*, which is then dereferenced to long. And this applies for any pointer type, including user-defined.
Wrong how. @Matthew? I've already stated that my suspicions weren't correct and that standard types worked okay. As to more complicated types, I haven't made a comment simply because it's not anything I've tried (or am likely to try).
Why did you post this when you voted to close? The dup had plenty of good answers, but you should have at least made this CW.
I posted this answer long before someone else found the dupe. Then I agreed with that decision to close after I checked out the dupe. It's not rocket science. And, really, it's not up to you to decide how people answer questions or whether they make them CW. It's up to the answerers themselves. If this was not a suitable question for SO, I would have gone CW (or more likely just left a comment) but this is a suitable question, just duplicated.
5

As Matthew Wilson discusses in Imperfect C++, this can be used to enforce type safety in C++, by preventing use of DIMENSION_OF()-like macros with instances of types that define the subscript operator, as in:

#define DIMENSION_OF_UNSAFE(x)  (sizeof(x) / sizeof((x)[0]))

#define DIMENSION_OF_SAFER(x)  (sizeof(x) / sizeof(0[(x)]))

int ints[4];

DIMENSION_OF_UNSAFE(ints); // 4
DIMENSION_OF_SAFER(ints); // 4

std::vector v(4);

DIMENSION_OF_UNSAFE(v); // gives impl-defined value; v likely wrong
DIMENSION_OF_SAFER(v); // does not compile

There's more to this, for dealing with pointers, but that requires some additional template smarts. Check out the implementation of STLSOFT_NUM_ELEMENTS() in the STLSoft libraries, and read about it all in chapter 14 of Imperfect C++.

edit: some of the commenters suggest that the implementation does not reject pointers. It does (as well as user-defined types), as illustrated by the following program. You can verify this by uncommented lines 16 and 18. (I just did this on Mac/GCC4, and it rejects both forms).

#include <stlsoft/stlsoft.h>
#include <vector>
#include <stdio.h>

int main()
{
    int     ar[1];
    int*    p = ar;
    std::vector<int>        v(1);

    printf("ar: %lu\n", STLSOFT_NUM_ELEMENTS(ar));

//  printf("p: %lu\n", STLSOFT_NUM_ELEMENTS(p));

//  printf("v: %lu\n", STLSOFT_NUM_ELEMENTS(v));

    return 0;
}

6 Comments

A better 'dimension' implementation can be achieved with templates: template <typename T, std::size_t N> std::size_t dimension( T[N]& x ) { return N; }. That will be safer than the sizeof(a)/sizeof(a[0]) with arrays (that have not decayed into pointers).
dribeas: the problem with that is that it's no longer a compile-time expression. The technique described by Wilson illustrates a compile-time version. As I said, it's available in the STLSoft libraries.
There is also a way to get a compile time expression: template<typename T, std::size_t N> char (& an_array(T(&)[N]) )[N]; That will evaluate to a reference to a char array having the same size. Use it like: int v[sizeof an_array(another_array)];
Note that both mine and dribea's macro are different from wilson's one, of course. Our one will reject a pointer. His one will accept it. Thus, these are different use cases.
tlib, dribeas: you're both wrong. See the edited response above.
|
0

In C and C++ (with array being a pointer or array) it is a language feature: pointer arithmetic. The operation a[b] where either a or b is a pointer is converted into pointer arithmetic: *(a + b). With addition being symetrical, reordering does not change meaning.

Now, there are differences for non-pointers. In fact given a type A with overloaded operator[], then a[4] is a valid method call (will call A::operator ) but the opposite will not even compile.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.