PWR086: Prefer array-based notation over pointer-based notation for readability
Issue
Using pointer increments or pointer assignments to access array elements reduces code readability and is more error-prone compared to equivalent array-based (index-based) notation.
Actions
Replace pointer-based array access patterns with array-based (index-based) notation.
Relevance
Pointer-based notation for accessing array elements is a common pattern in C and C++ code. While functionally equivalent to array-based notation, pointer-based access introduces unnecessary complexity that harms code quality:
- Error-proneness: pointer arithmetic is a frequent source of off-by-one
errors and out-of-bounds accesses, especially when accessing multi-dimensional
arrays with a single pointer
*, where offsets must be manually computed by multiplying indices with the corresponding dimensions. Array-based notation makes the intent explicit and reduces the chance of such mistakes. - Readability: understanding which element of the array is being accessed requires mentally tracking the pointer's value across modifications in the control flow. With array-based notation, the accessed element is immediately clear from the index expression.
- Maintainability: changing access regions is significantly harder when pointer arithmetic must be updated in tandem. Array-based notation keeps the indexing logic self-contained and localized.
Code example
The following loop uses a pointer increment to walk through the elements of
array b:
void example(float *a, float *b, float *c, unsigned size, unsigned inc) {
float *bTemp1 = b;
for (unsigned i = 0; i < size; i++) {
c[0] += (a[i] * bTemp1[0]);
bTemp1 -= inc;
}
}
The pointer bTemp1 is decremented by inc on every iteration, making it
difficult to see at a glance which element of b is accessed in each iteration.
Replacing the pointer notation with array indexing makes the access pattern
explicit:
void solution(float *a, float *b, float *c, unsigned size, unsigned inc) {
for (unsigned i = 0; i < size; i++) {
c[0] += (a[i] * b[(int)(-i * inc));
}
}
Now the relationship between the loop variable i and the accessed element of
b is immediately visible.
Related resources
- PWR086 examples
- PWR028: Remove pointer increment preventing performance optimization
- PWR030: Remove pointer assignment preventing performance optimization for perfectly nested loops