Passing Arrays
Array Decay Pitfalls
When arrays are passed to functions by value-like syntax, they decay to pointers and lose their extent (size) information. Consequences:
1. Size must be passed separately (or recovered via another mechanism).
2. No bounds checking via `operator[]`.
3. You cannot use range-based `for` on the **decayed pointer alone** (you need a size/range).
4. Template type deduction loses the array bound unless you pass the array by reference.
// What you write
void process(int arr[5]);
// What the compiler sees (array bound is ignored)
void process(int* arr);
// Preserve size with a reference (captures N)
template <std::size_t N>
void process_ref(int (&arr)[N]) {
// now N is known; range-for works
for (int x : arr) {/*...*/}
}
Modern Alternatives
Prefer these over C-style array parameters:
Type | Size Handling | Bounds Checking |
---|---|---|
std::array | Fixed at compile-time | Optional via at(); operator[] unchecked |
std::vector | Dynamic (resizable) | Optional via at(); operator[] unchecked |
std::span (C++20) | Runtime size (non-owning view) | No built-in checks; use size()/algorithms |
Using std::span for Parameters (C++20)
`std::span
#include <span>
#include <vector>
#include <array>
void process(std::span<const int> nums) {
// size is available; safe iteration
for (int x : nums) {/*...*/}
}
void demo() {
int raw[3] = {1,2,3};
std::array<int,3> a{1,2,3};
std::vector<int> v{1,2,3};
process(raw); // decays to span
process(a); // converts to span
process(v); // converts to span
}
Preserving Size with References (Templates)
If you cannot use C++20, pass arrays by reference to capture their extent at compile time.
#include <cstddef>
template <class T, std::size_t N>
void fill_with_zero(T (&arr)[N]) {
for (std::size_t i = 0; i < N; ++i) arr[i] = T{};
}
void use() {
int a[10];
fill_with_zero(a); // N deduced as 10
}
Multidimensional Arrays
Passing multidimensional arrays requires keeping the rightmost bound(s) known to the function.
Prefer references or `std::array` for fixed sizes.
// Pointer form: column count must be known
void process(int (*matrix)[10], int rows) {
// matrix points to an array of 10 ints per row
}
// Reference template: captures both dimensions
template <std::size_t R, std::size_t C>
void process(int (&matrix)[R][C]) {
// R and C are known; range-for works
}
// Using std::array for truly fixed sizes
#include <array>
void process(std::array<std::array<int,10>,10>& matrix) {
// fixed 10x10
}
Common Pitfall: `int**` is NOT `int[][M]`
`int**` does not model a contiguous 2D array created as `int a[R][C];`. Passing `a` to a function taking `int**` is ill-formed/incorrect because the memory layouts differ. Use one of the correct forms above, or flatten to 1D with manual indexing.