Arrays
Every chapter so far has shown small toolchain and syntax differences from Rust. This one is different — arrays are where C's total absence of a safety net becomes something you can actually see happen.
Declaring & Initializing Arrays
A plain C array has a fixed size, known at compile time — genuinely comparable to Rust's own fixed-size [T; N] array (not Vec, which can grow). Both languages have this exact concept. What happens when you go past the end is where they stop agreeing.
No Bounds Checking — The Real Difference
Accessing values[10] on a 5-element array is not an error in C. It's not a panic. It compiles, it runs, and it reads or writes whatever memory happens to sit past the array — memory that belongs to something else entirely. Rust's [T; N], by contrast, checks every index access at runtime and panics on an out-of-bounds index — a controlled, visible failure instead of silent memory corruption.
A Concrete Demonstration
Two adjacent local variables often sit next to each other in memory. Writing past the end of one array can silently overwrite the other — no error, no warning, just a value that changed for no visible reason.
Course 2's Memory Bugs chapter covers this class of problem in full, with real tooling (valgrind) to catch it. For now, the point is simpler: C genuinely will not stop this.
Array-to-Pointer Decay, Previewed
Chapter 5 established pass-by-value as C's default. Arrays quietly break that rule: passing an array to a function actually passes a pointer to its first element, not a copy of the whole array. Chapter 7 covers pointers in full — this is just naming the exception now, so it doesn't feel unexplained later.
Getting the Array's Size
sizeof(arr) / sizeof(arr[0]) computes the element count — but only where the array was actually declared. Once it decays to a pointer (inside a function it was passed to), sizeof on the parameter gives the pointer's size, not the array's.
| Concept | Rust [T; N] | C |
|---|---|---|
| Fixed size, known at compile time | yes | yes |
| Out-of-bounds access | panics — a controlled, visible failure | undefined behavior — silent, no check at all |
| Passed to a function | by value (or reference, explicit) — stays a real array | decays to a pointer to the first element |
sizeof(arr) / sizeof(arr[0]) only works in the scope where the array itself was declared. Compute it there, and pass the count as a separate parameter — a genuinely common, real beginner trap otherwise.
Coding Challenges
Declare an int array of 6 elements, initialize it with values, and print each element using a for loop and the sizeof(arr)/sizeof(arr[0]) trick to determine the loop bound.
📄 View solutionDeclare a 3-element array and a separate int variable directly after it. Write past the end of the array (e.g. arr[4] or arr[5]) and print the separate variable afterward. Explain what you observe and why C allows it.
📄 View solutionExplain why sizeof(arr)/sizeof(arr[0]) gives the correct element count in the function where an array is declared, but gives a wrong answer if computed inside a different function the array was passed into.
📄 View solutionChapter 6 Quick Reference
- C arrays are fixed-size, known at compile time — genuinely comparable to Rust's
[T; N] - No bounds checking, ever — an out-of-range access is undefined behavior, not an error or a panic
- Rust's
[T; N]checks every access and panics on out-of-bounds — the central contrast this chapter exists to demonstrate - Arrays passed to a function decay to a pointer to the first element — breaking Chapter 5's pass-by-value rule
sizeof(arr)/sizeof(arr[0])only works where the array was declared — not after it decays to a pointer- Next chapter: pointers — the mechanism arrays already quietly depend on