Ch5.5: C‑style Arrays
Overview
A C‑style array is a fixed‑size sequence of elements stored in one contiguous block of memory. Arrays are the foundation for pointer arithmetic, array decay, and C‑style strings, so it is essential to understand how they behave in memory.
In this chapter, you will learn:
- how to declare and initialize C‑style arrays
- how arrays are laid out in memory
- how to access elements safely
- why out‑of‑bounds access is undefined behavior
- why
::fast_io::arrayand::fast_io::vectorare safer choices - why arrays and pointers are related but not the same
1. Declaring a C‑style array
A C‑style array is declared by specifying the element type and the number of elements:
int a[3]; // array of 3 ints
char b[10]; // array of 10 chars
double c[4]; // array of 4 doubles
The size must be known at compile time, and it must be greater than 0.
// int a[0]; // error: C-style arrays cannot have size 0
2. Initializing arrays
You can initialize arrays using brace‑initialization:
int a[3]{10, 20, 30};
If you provide fewer elements, the rest are zero‑initialized:
int a[5]{1, 2}; // becomes {1, 2, 0, 0, 0}
If you omit the size, the compiler deduces it:
int a[]{10, 20, 30}; // size is 3
3. Arrays are contiguous in memory
All elements of an array are stored next to each other in memory.
int a[3]{10, 20, 30};
Example memory layout (addresses vary):
Address: 1000 1004 1008
Memory: [ 10 ] [ 20 ] [ 30 ]
↑ ↑ ↑
a[0] a[1] a[2]
This contiguity is what makes pointer arithmetic possible (covered in Ch5.6).
4. Accessing array elements
You access elements using the [] operator:
int a[3]{10, 20, 30};
int x = a[0]; // 10
int y = a[2]; // 30
a[1] = 99; // a becomes {10, 99, 30}
5. Out‑of‑bounds access is undefined behavior
C‑style arrays do not perform bounds checking. Accessing outside the array is undefined behavior.
int a[3]{10, 20, 30};
// a[3]; // undefined behavior — out of bounds
// a[-1]; // undefined behavior
Undefined behavior means:
- the program might crash
- or corrupt memory
- or silently produce wrong results
- or appear to work
You cannot rely on any specific outcome.
WebAssembly note
On WebAssembly without memory tagging, out‑of‑bounds array access often does not trap, making bugs harder to detect.
6. fast_io::array vs C‑style arrays
::fast_io::array is a safer and more flexible alternative to C‑style arrays.
- It performs bounds checking for
[]access. - It allows zero‑sized arrays, which C‑style arrays do not.
#include <fast_io_dsal/array.h>
::fast_io::array<int, 0> empty; // valid: zero-sized array
Normal element access is checked:
::fast_io::array<int, 3> arr{10, 20, 30};
int x = arr[1]; // safe: bounds checked
If you intentionally want unchecked access (for performance‑critical code),
::fast_io::array provides:
int x = arr.index_unchecked(1); // no bounds checking
For most code, prefer arr[i] with bounds checking.
7. fast_io::vector as the default container
For most dynamic sequences of elements, prefer ::fast_io::vector.
It manages its own size and capacity and also supports bounds‑checked access.
#include <fast_io_dsal/vector.h>
::fast_io::vector<int> vec;
vec.push_back(10);
vec.push_back(20);
int x = vec[0]; // bounds checked
When you need unchecked access for performance‑critical code,
::fast_io::vector also provides:
int x = vec.index_unchecked(0); // no bounds checking
For most code, prefer vec[i] with bounds checking and reserve
index_unchecked() for carefully reviewed hot paths.
8. Arrays and pointers are related but not the same
Arrays and pointers are closely related, but they are not the same.
An array:
- is a fixed block of memory
- knows its size at compile time
- cannot be reassigned
A pointer:
- stores an address
- can point to different objects
- does not know the size of the array it points to
We will explore the relationship between arrays and pointers in detail in Ch5.7: Array Decay.
9. Getting the address of array elements
You can obtain the address of any element using ::std::addressof:
#include <memory>
int a[3]{10, 20, 30};
int *p0 = ::std::addressof(a[0]);
int *p1 = ::std::addressof(a[1]);
int *p2 = ::std::addressof(a[2]);
Addresses (example):
p0 = 1000
p1 = 1004
p2 = 1008
This layout is what makes pointer arithmetic meaningful (next chapter).
10. Arrays cannot be copied or assigned
C‑style arrays cannot be copied or assigned using =.
int a[3]{1, 2, 3};
int b[3];
// b = a; // error: arrays cannot be assigned
Copying arrays requires manual element‑by‑element copying or memcpy
(covered in Ch5.14).
Key takeaways
- A C‑style array is a fixed‑size, contiguous block of memory.
- C‑style arrays cannot have size 0.
- Array elements are accessed with
[]. - Out‑of‑bounds access is undefined behavior.
- Undefined behavior does NOT guarantee a crash.
::fast_io::arrayperforms bounds checking for[]and supports zero‑sized arrays.arr.index_unchecked()andvec.index_unchecked()provide unchecked access when needed.- Prefer
::fast_io::vectoras your default container. - Prefer
::fast_io::arrayover C‑style arrays. - Arrays and pointers are related but not the same.
- This chapter prepares you for pointer arithmetic (Ch5.6) and array decay (Ch5.7).