|
| 1 | +# PWR086: Prefer array-based notation over pointer-based notation for readability |
| 2 | + |
| 3 | +### Issue |
| 4 | + |
| 5 | +Using pointer increments or pointer assignments to access array elements reduces |
| 6 | +code readability and is more error-prone compared to equivalent array-based |
| 7 | +(index-based) notation. |
| 8 | + |
| 9 | +### Actions |
| 10 | + |
| 11 | +Replace pointer-based array access patterns with array-based (index-based) |
| 12 | +notation. |
| 13 | + |
| 14 | +### Relevance |
| 15 | + |
| 16 | +Pointer-based notation for accessing array elements is a common pattern in C and |
| 17 | +C++ code. While functionally equivalent to array-based notation, pointer-based |
| 18 | +access introduces unnecessary complexity that harms code quality: |
| 19 | + |
| 20 | +- **Error-proneness**: pointer arithmetic is a frequent source of off-by-one |
| 21 | + errors and out-of-bounds accesses, especially when accessing multi-dimensional |
| 22 | + arrays with a single pointer `*`, where offsets must be manually computed by |
| 23 | + multiplying indices with the corresponding dimensions. Array-based notation |
| 24 | + makes the intent explicit and reduces the chance of such mistakes. |
| 25 | +- **Readability**: understanding which element of the array is being accessed |
| 26 | + requires mentally tracking the pointer's value across modifications in the |
| 27 | + control flow. With array-based notation, the accessed element is immediately |
| 28 | + clear from the index expression. |
| 29 | +- **Maintainability**: changing access regions is significantly harder when |
| 30 | + pointer arithmetic must be updated in tandem. Array-based notation keeps the |
| 31 | + indexing logic self-contained and localized. |
| 32 | + |
| 33 | +### Code example |
| 34 | + |
| 35 | +The following loop uses a pointer increment to walk through the elements of |
| 36 | +array `b`: |
| 37 | + |
| 38 | +```c |
| 39 | +void example(float *a, float *b, float *c, unsigned size, unsigned inc) { |
| 40 | + float *bTemp1 = b; |
| 41 | + for (unsigned i = 0; i < size; i++) { |
| 42 | + c[0] += (a[i] * bTemp1[0]); |
| 43 | + bTemp1 -= inc; |
| 44 | + } |
| 45 | +} |
| 46 | +``` |
| 47 | +
|
| 48 | +The pointer `bTemp1` is decremented by `inc` on every iteration, making it |
| 49 | +difficult to see at a glance which element of `b` is accessed in each iteration. |
| 50 | +Replacing the pointer notation with array indexing makes the access pattern |
| 51 | +explicit: |
| 52 | +
|
| 53 | +```c |
| 54 | +void example(float *a, float *b, float *c, unsigned size, unsigned inc) { |
| 55 | + for (unsigned i = 0; i < size; i++) { |
| 56 | + c[0] += (a[i] * b[-i * inc]); |
| 57 | + } |
| 58 | +} |
| 59 | +``` |
| 60 | + |
| 61 | +Now the relationship between the loop variable `i` and the accessed element of |
| 62 | +`b` is immediately visible. |
| 63 | + |
| 64 | +> [!TIP] |
| 65 | +> Array-based notation also enables compiler optimizations such as automatic |
| 66 | +> vectorization and loop interchange. See [PWR028](../PWR028/README.md) and |
| 67 | +> [PWR030](../PWR030/README.md) for performance-focused checks covering the |
| 68 | +> same code patterns. |
| 69 | +
|
| 70 | +### Related resources |
| 71 | + |
| 72 | +* [PWR086 examples](https://github.com/codee-com/open-catalog/tree/main/Checks/PWR086/) |
| 73 | +* [PWR028: Remove pointer increment preventing performance optimization](../PWR028/README.md) |
| 74 | +* [PWR030: Remove pointer assignment preventing performance optimization for perfectly nested loops](../PWR030/README.md) |
| 75 | + |
| 76 | +### References |
| 77 | +* [CWE-468: Incorrect Pointer Scaling](https://cwe.mitre.org/data/definitions/468.html) |
0 commit comments