20

In C, when is it preferrable to use one over the other?

1
  • You may find this one handy! Commented Jul 24, 2012 at 6:24

6 Answers 6

20

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.

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

7 Comments

Is there any time measurement of execution between these two?
For the compiler, when optimizing, it is exactly the same.
@BasileStarynkevitch Not just then, C11 specifies &p[i] to behave identically to p + i, even if p is a NULL pointer or something to that effect.
@fuz p + i has undefined behaviour if p is NULL though, right? So it's pretty meaningless to say that &p[i] behaves "identically" in that case. More correct is that it also has undefined behaviour. In any case I don't see how your comment applies to this answer... what do you mean by "not just then"?
@fuz fair enough; perhaps you should delete it.
|
14

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.

Comments

11

"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.

Comments

3

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.

Comments

0

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.

1 Comment

I didn't downvote personally, but I believe the question is asking about the use of *(p + i) versus p[i] notations, not about whether you should declare an array or a pointer to refer to the data in the first place.
-1

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 ] );

2 Comments

This question is tagged C, not C++. And even if it wasn't, MISRA compliance is by no means necessary.
Also please note that the cited rule has been removed in MISRA-C:2012 since it didn't make any sense, there was no rationale for it. (Yours sincerely among others insisted to the committee that this rule should get removed) It has been replaced by much better rules in chapter 18.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.