Track 4 · Solidity foundations · lesson 7
Arrays and structs
10 min
Mappings answer "what is the value for this key?". Arrays answer "what have I got, and how many?".
uint256[] public scores; // grows and shrinks
uint256[5] public fixedScores; // exactly five, forever
Dynamic arrays support .push(), .pop() and .length. Fixed-size ones
support none of that, and are cheaper because their size is known at compile
time.
Nudge
Show me the approach
Show me the code
Explain the solution
The loop you just wrote is a liability
That for loop is correct, and in production it is a genuine hazard.
Gas grows with the number of elements. Ten scores is nothing. Ten thousand is a function that costs more gas than a block permits — at which point it can never be called again, by anyone, ever.
The contract is not broken. It is frozen, permanently, and no upgrade can retrieve funds it is holding.
The habit to build: never loop over an array that anyone else can grow. If
strangers can call add(), your loop has an attacker-controlled length. Keep a
running total instead, or make each user pull their own share.
Predict
A charity contract loops over all donors to pay them a refund. What could an attacker do?
Structs
A struct groups related fields under one name:
struct Task {
string title;
bool done;
address owner;
}
Task[] public tasks;
mapping(uint256 => Task) public taskById;
Structs are how you avoid five parallel arrays that must be kept in step — a pattern that goes wrong the first time one of them is updated and another is not.
Check
Why is `uint256[5]` cheaper than `uint256[]`?
Worth remembering
- Dynamic arrays support push, pop and length; fixed-size arrays are cheaper but cannot change size.
- Looping over an array costs gas proportional to its length.
- Never loop over an array that other people can grow — that is a denial-of-service waiting to happen.
- Prefer the pull pattern: let each user claim their own share.
- Structs group related fields and prevent parallel arrays drifting out of step.