In C, when is it preferrable to use one over the other?
It is really a matter of style and of coding conventions, since in C p[i]
is defined to be the same as *(p+i)
where p
is a pointer and i
an integral index. AFAIK you could even write i[p]
but that is ugly.
This is not always true in C++ (which gives you the power of defining operator []
etc...).
I personally dislike hand-coding &p[i]
and prefer p+i
in that case.
in according to MISRA C++ 2008 (Rule 5-0-15): Array indexing shall be the only form of pointer arithmetic.
but this rule has an exception:
The increment/decrement operators may be used on iterators implemented by pointers to an array
template < typename IterType >
uint8_t sum_values ( IterType iter, IterType end )
{
uint8_t result = 0;
while ( iter != end )
{
result += *iter;
++iter; // Compliant by exception
}
return result;
}
void my_fn ( uint8_t * p1, uint8_t p2[ ] )
{
uint8_t index = 0;
uint8_t * p3;
uint8_t * p4;
*p1 = 0;
++index;
index = index + 5;
p1 = p1 + 5; // Non-compliant – pointer increment
p1[ 5 ] = 0; // Non-compliant – p1 was not declared as array
p3 = &p1[ 5 ]; // Non-compliant – p1 was not declared as array
p2[ 0 ] = 0;
p2[ index ] = 0; // Compliant
p4 = &p2[ 5 ]; // Compliant
}
uint8_t a1[ 16 ];
uint8_t a2[ 16 ];
my_fn ( a1, a2 );
my_fn ( &a1[ 4 ], &a2[ 4 ] );
uint8_t a[ 10 ];
uint8_t * p;
p = a;
*( p + 5 ) = 0; // Non-compliant
p[ 5 ] = 0; // Compliant
sum_values ( &a1[ 0 ], &a1[ 16 ] );
Pointers are useful when the size of the data structure is not known at compile time. e.g. when you do not know what is the length of a string, or how many integers you are expecting and so on. In such situations, pointers can be dynamically allocated memory depending on the requirements.
Arrays on the other hand, reduce the flexibility.
There is much more beyond this difference though.
In terms of performance, it can be better to use pointer arithmetic (at least with compiler optimization disabled), because when iterating over an array, you don't have to increment a separate variable. See also K&R page 97 (second edition).
Otherwise it is simply a question of coding style.
"Array indexing" is just syntactic sugar that wraps "pointer arithmetic". It is purely cosmetic, just another notation, meaning that using one or another would be a matter of personal preference.
The real question that usually hides behind what you asked is when to use random access and when to use sequential access (with "pointer arithmetic" implying sequential increment/decrement of a pointer by no more than 1). The answer is: prefer to use sequential access when you can, only use random access when you must.
As long as performance doesn't suffer, it is always a better idea to implement algorithms by relying on the minimal set of requirements. Random access is a stronger requirement than sequential access, meaning that the former should be avoided when reasonably possible.
It usually depends on the situation. I don't think there's a rule of thumb.
In some cases, array indexes are better. For example when you have allocated an array
char* ptr = malloc(SIZE);
and you need the value of ptr
to not change, because you want to free it later, then you can work with indexes.
Or if you get a pointer as a function argument
void func(char* ptr)
and you need to run over the array, then you can increment the pointer itself and you won't need to create a new variable to use as an index.
In most cases however, it depends on your own preferences.