Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do pointers support "array style indexing"?

(Self-answered Q&A - this matter keeps popping up)

I assume that the reader is aware of how pointer arithmetic works.

int arr[3] = {1,2,3};
int* ptr = arr;
...
*(ptr + i) = value;

Teachers/C books keep telling me I shouldn't use *(ptr + i) like in the above example, because "pointers support array style indexing" and I should be using ptr[i] = value; instead. No argument there - much easier to read.

But looking through the C standard, I find nothing called "array style indexing". In fact, the operator [] is not expecting either operand to be an array, but instead a pointer or an integer!

6.5.2.1 Array subscripting

Constraints

One of the expressions shall have type ‘‘pointer to complete object type’’, the other expression shall have integer type, and the result has type ‘‘type’’.

Why does the array subscripting operator not expect an array? Is the standard wrong? Is my teacher/C book confused?

like image 492
Lundin Avatar asked Apr 18 '19 14:04

Lundin


People also ask

Can pointers be indexed?

The C++ language allows you to perform integer addition or subtraction operations on pointers.

Is pointer arithmetic faster than array indexing?

Pointer arithmetic is slightly faster (about %10) than array indexing.

Are index and pointer the same thing?

The index finger (also referred to as forefinger, first finger, second finger, pointer finger, trigger finger, digitus secundus, digitus II, and many other terms) is the second digit of a human hand.

Can array and pointer be used interchangeable?

Arrays and pointers are never the same thing. However, under certain circumstances, an array name in your code will "decay" to a pointer to the first element.


1 Answers

You should indeed be using ptr[i] over *(ptr + i) for readability reasons. But apart from that, the [] operator is, strictly speaking, actually never used with an array operand.

Arrays, when used in an expression, always "decay" into a pointer to the first element (with some exceptions). C17 6.3.2.1/3, emphasis mine:

Except when it is the operand of the sizeof 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.

Meaning that whenever you type arr[i], the operand arr gets replaced by a pointer to the first element inside that array. This is informally referred to as "array decaying". More info here: What is array decaying?

So whenever you use the [] operator, you use it on a pointer. Always.

The C standard says that this operator is guaranteed to be equivalent to the pointer arithmetic (C17 6.5.2.1/2):

The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2))).

So whenever we type arr[i], it actually gets silently replaced by *(arr+i). Where arr is still a pointer to the first element.

And this is why the description you quoted tells you that either operand could be a pointer and the other an integer. Because obviously it doesn't matter if we type *(arr+i) or *(i+arr) - that's equivalent code.

Which in turn allows us to write obfuscated "joke" code like i[arr], which is actually valid C and fully equivalent to arr[i]. But don't write such code in real applications.

like image 187
Lundin Avatar answered Sep 21 '22 15:09

Lundin