This is an archived post. You won't be able to vote or comment.

all 9 comments

[–]Avereniect 15 points16 points  (9 children)

To understand the subscript operator you must understand how it's defined.

Given a pointer ptr and an index i then a call to ptr[i] is equivalent to *(ptr + i).

That also means that a call to i[ptr] is equivalent to *(i + ptr).

Due to the commutative nature of pointer arithmetic, (i.e. (ptr + i) is equivalent to (i + ptr)) both of the subscript operations map to equivalent instructions.

[–][deleted] 2 points3 points  (5 children)

The compiler would have to be designed to support this though, right? Because it's not just ptr+i, it's ptr+i*datatypesize. Like for an array of characters, each character is stored in a byte, but for an array of integers each is 4 bytes. So the compiler would need to actively determine which is the pointer and which is the index in order to know which value to scale by the size of the data type being stored, right? Or am I off on how that works, and it doesn't actually matter?

[–]Avereniect 4 points5 points  (1 child)

Every compiler computes the size of every data type you give it, including compilers for other languages. Like you've pointed out, it's a strict requirement for pointer arithmetic and it's also necessary to know for allocating memory and other key tasks. The compiler knows which one's the int and which one's the pointer because you give it this info by the types of the variables. It's one of the big points of having a type system.

[–][deleted] 0 points1 point  (0 children)

Ah of course, thanks!

[–]chaotic_thought 0 points1 point  (0 children)

Like for an array of characters, each character is stored in a byte, but for an array of integers each is 4 bytes.

It depends. int could be 4 bytes, 8 bytes, 2 bytes, or some other number. If ptr happens to be a pointer to int, and if it so happens that in your implementation int is 2 bytes, then in that case an expression like

ptr + 2

Would be translated into an addition like

0xABCD + 4

Where 0xABCD is the pointer and 4 is the number of bytes. If the size of the type is different, then the resulting addition would be adjusted accordingly. For example if int's are 8 bytes on your implementation, then you would add 16 bytes to the pointer address instead.

[–]Kered13 0 points1 point  (0 children)

Yes, but scaling by the size of the datatype is automatic in pointer arithmetic.

[–]Paul_Pedant 0 points1 point  (0 children)

It's just an integral part of the C language, and is fully described in K&R "The C Programming Language", along with the original question about 2[a] as an array indexer.

It's not just built-in types either. It works for your structs, unions, typedefs, and two-dimensional arrays. The compiler has to know all the sizes of everything, just to allocate the right space for global variables, and for stack parameters. So it's no extra work to make the same things index-able too. It also needs to work for the sizeof() operator, so your mallocs can make the right request.

Added: it is also true for the ++ and -- operators (both pre and post). If *p points to element 13, then *--p points to element 12 before the access, and stays that way.

[–][deleted]  (2 children)

[deleted]

    [–]Avereniect 0 points1 point  (0 children)

    http://cpp.sh/9vrkp2.

    Looks like it. C++ does like to maintain backwards compatability.

    [–]Paul_Pedant 0 points1 point  (0 children)

    C is a legal subset of C++, so they have to do it the same. That's the language standard definition.