1D Arrays Grade 11
Imagine you need to store 30 student marks. Without arrays you would need 30 separate variables — iMark1, iMark2, … iMark30. With an array, one name stores them all: arrMarks[1..30]. Arrays are a Grade 11 Term 1 topic.
Why Use Arrays?
What is a 1D Array?
A one-dimensional array is a structured data type that stores a fixed number of values of the same data type under a single variable name, with each individual value accessed using its own index (a whole number giving that value's position in the list).
Think of an array like a train: each carriage (box) holds one value and is numbered by its index — the index tells you exactly where to find that value.
Remember a single variable is one cup. An array is a whole matching dinner set — say 6 cups — that all share one name and are numbered: arrCups[1], arrCups[2] … arrCups[6]. Every item is the same type (all cups), just at a different index (place-setting number).
So instead of naming 30 separate cups cup1, cup2, …, you keep one name and pick the one you want by its number: arrMarks[7] is simply "the mark at place setting 7".
Declaring an Array
arrName : array [lowerIndex..upperIndex] of DataType;var
arrNames : array [1..30] of String;
arrMarks : array [1..30] of Integer;
arrPrices : array [0..9] of Real;Arrays of Unknown Length — use a constant
You don't always know in advance exactly how many items you will store. A common trick is to declare a constant for the maximum size, then use it as the upper index. If the size needs to change later, you only edit one line.
The constant must be declared above the array declaration (it can go just above type in the interface section), otherwise Delphi won't know what Max means yet.
const
Max = 100; // maximum possible learners
var
arrNames : array [1..Max] of String;
iCount : Integer; // how many are ACTUALLY usedKeep a separate counter (iCount) for how many elements are really in use, and loop 1 to iCount instead of 1 to Max.
Dynamic Arrays
A dynamic array has no fixed size when declared — you set (and can later change) its length while the program runs with SetLength. This is perfect when the number of items is only known at runtime (e.g. after reading a file).
Unlike array[1..30], a dynamic array is always 0-based. If you SetLength(arr, 5) the valid indexes are 0,1,2,3,4. Use Low(arr) for the first index (0) and High(arr) for the last (length − 1).
| Routine | Purpose |
|---|---|
SetLength(arr, n) | Sets (or changes) the array to hold n elements |
Length(arr) | Returns the current number of elements |
Low(arr) | First valid index (always 0 for dynamic arrays) |
High(arr) | Last valid index (Length − 1) |
var
arrNum : array of Integer; // note: NO index range given
i : Integer;
begin
SetLength(arrNum, 5); // now holds 5 ints, index 0..4
for i := Low(arrNum) to High(arrNum) do
arrNum[i] := i * 2; // 0, 2, 4, 6, 8
SetLength(arrNum, 8); // grow to 8 — existing values are kept
end;Populating an Array
Method 1: Fixed values
arrNames[1] := 'Alice';
arrNames[2] := 'Bob';
arrNames[3] := 'Callie';Method 2: Constant array (known at compile time)
const
arrDays : array [1..7] of String =
('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun');Method 3: User input with a loop
for i := 1 to 30 do
arrNames[i] := InputBox('Name', 'Enter name:', '');Displaying & Calculating
// Display all
for i := 1 to Length(arrMarks) do
memOut.Lines.Add(IntToStr(arrMarks[i]));
// Sum and average
iTotal := 0;
for i := 1 to Length(arrMarks) do
iTotal := iTotal + arrMarks[i];
rAvg := iTotal / Length(arrMarks);Shortcut: the Math Unit
Writing your own loop to total or average an array works, but Delphi's Math unit already has ready-made functions that do the same job in one line.
| Function | Returns |
|---|---|
Sum(arr) | Total of every element |
Mean(arr) | Average of every element |
MaxValue(arr) | The largest value in the array |
MinValue(arr) | The smallest value in the array |
uses Math; // add this to the uses clause first
rAvg := Mean(arrPrices);
rTotal := Sum(arrPrices);
rHighest := MaxValue(arrPrices);
rLowest := MinValue(arrPrices);These four functions only accept an array whose elements are declared as Double — not Integer, and not the general-purpose Real. If your array holds integers, either redeclare it as array[1..n] of Double, or stick to your own loop.
Arrays with Meaningful Indices
Every index used so far has just meant "the Nth item in the list" — arrNames[3] is simply whoever happens to be third. Sometimes, though, it's more useful to let the index itself carry meaning. If arrVotes[4] always holds the vote count for competitor number 4, the index is the competitor number, not just a position in a queue.
Using a Char as the Index
An index isn't limited to whole numbers — any ordinal type can be used, including Char. This is handy whenever the letter itself is what you want to look values up by, e.g. tallying how many learners scored each grade symbol (A to F) in a test:
var
arrSymbolCount : array ['A'..'F'] of Integer;
cGrade : Char;
begin
cGrade := 'A';
while cGrade <= 'F' do
begin
arrSymbolCount[cGrade] := 0; // reset every element to zero first
cGrade := succ(cGrade); // moves 'A' to 'B', 'B' to 'C', and so on
end;
// later, whenever a learner's symbol is worked out:
Inc(arrSymbolCount[cLearnerSymbol]);succ(cGrade) gives the character that comes after cGrade in the alphabet; pred(cGrade) gives the one before it. They work like +1/-1 for any ordinal type, including Char, where plain arithmetic isn't allowed.
Matching a RadioGroup's ItemIndex to an Array
A RadioGroup's ItemIndex always starts counting from 0 for its first button — but an array you declare yourself might start at 1. When you use ItemIndex to pick an element to update (for example, tallying votes for a menu option), you need to decide which convention your array follows and stay consistent:
Array declared [0..4] | Array declared [1..5] |
|---|---|
iChoice := rgpMenu.ItemIndex;Inc(arrVotes[iChoice]); |
iChoice := rgpMenu.ItemIndex + 1;Inc(arrVotes[iChoice]); |
With the [1..5] version, the array index is always one more than ItemIndex, because ItemIndex itself never moves off its 0-based counting — only your array's lower bound changes.
Delphi will happily compile arrNames[50] even if arrNames was declared as [1..30] — the mistake only surfaces while the program is running, as a range-check/IndexOutOfBounds error the moment that line executes. Whenever an index comes from user input or from a component like ItemIndex, validate it against the array's real bounds before using it.
Linear Search
bFound := False;
for i := 1 to Length(arrNames) do
if arrNames[i] = sSearch then
begin
ShowMessage('Found at position ' + IntToStr(i));
bFound := True;
Break;
end;
if not bFound then
ShowMessage('Not found');The code above stops the loop with Break as soon as one match turns up — correct when you only expect a single match (e.g. one learner's ID number). If instead you needed every occurrence (e.g. every learner who chose "Physics"), you would drop the flag and Break, and simply let the loop run to the end, adding each match found along the way. Once the array is sorted, binary search (below) beats both approaches for speed.
Binary Search (sorted array)
Binary search is much faster than linear — it halves the search range each step. The array must be sorted first. We are searching for 23 in the array [2, 5, 8, 12, 16, 23, 38, 56, 72, 91].
iLow := 1;
iHigh := Length(arrNums);
bFound := False;
while (iLow <= iHigh) and not bFound do
begin
iMid := (iLow + iHigh) div 2;
if arrNums[iMid] = iTarget then
bFound := True
else if arrNums[iMid] < iTarget then
iLow := iMid + 1
else
iHigh := iMid - 1;
end;
if bFound then
ShowMessage('Found at position ' + IntToStr(iMid));How String Comparison Works
Sorting a string array with > and < only makes sense once you know what Delphi is actually comparing. It never looks at "the alphabet" directly — it walks each string letter by letter and compares the underlying ASCII value of each character, stopping at the first pair of letters that differ.
| Comparison | Result | Why |
|---|---|---|
'Alice' = 'alice' | False | 'A' is ASCII 65, 'a' is ASCII 97 — string comparison is case-sensitive. |
'Bob' < 'Eve' | True | First letters differ straight away: 'B' (66) is less than 'E' (69). |
'Farai' < 'Farm' | True | The first three letters ('F','a','r') match, so the 4th letter decides: 'a' (97) is less than 'm' (109). |
'Gio' > 'Gi' | True | Delphi pads the shorter string with trailing spaces to compare them — so 'Gi' becomes 'Gi ', and 'o' (111) beats a space (32). |
Because every uppercase letter has a lower ASCII value than every lowercase letter, an unsorted mix of cases will group all the capitalised words before any lowercase word once sorted — not what most people expect from "alphabetical order". If that matters, convert both sides to the same case (e.g. with UpperCase()) before comparing or sorting.
Bubble Sort — Pass by Pass
Bubble sort compares adjacent elements and swaps them if they are in the wrong order. After each full pass, the largest unsorted value "bubbles" to its correct position at the end. Array: [5, 3, 8, 1, 9] — sorting ascending.
for i := Length(arrNums) - 1 downto 1 do
for j := 1 to i do
if arrNums[j] > arrNums[j + 1] then
begin
iTemp := arrNums[j];
arrNums[j] := arrNums[j + 1];
arrNums[j + 1] := iTemp;
end;The version above always completes every single pass, even once the array is already sorted. A smarter bubble sort keeps a Boolean flag and quits the moment a whole pass goes by with no swaps at all — because that can only happen when the array is fully sorted:
iEndCounter := Length(arrNums) - 1;
repeat
bSwapped := False;
for j := 1 to iEndCounter do
if arrNums[j] > arrNums[j + 1] then
begin
iTemp := arrNums[j];
arrNums[j] := arrNums[j + 1];
arrNums[j + 1] := iTemp;
bSwapped := True;
end;
Dec(iEndCounter); // the tail end is sorted, so search one less item next time
until not bSwapped; // no swaps this pass = fully sorted, stop loopingSelection Sort — Pass by Pass
Selection sort finds the smallest remaining element and swaps it into its correct position. Same array: [5, 3, 8, 1, 9].
for i := 1 to Length(arrNums) - 1 do
begin
iMin := i;
for j := i + 1 to Length(arrNums) do
if arrNums[j] < arrNums[iMin] then
iMin := j;
if iMin <> i then
begin
iTemp := arrNums[i];
arrNums[i] := arrNums[iMin];
arrNums[iMin] := iTemp;
end;
end;Parallel Arrays
Two arrays are parallel when the same index refers to the same "record" — e.g. arrNames[3] and arrMarks[3] both belong to the same student. When you sort one, you must sort both to keep them in sync.
At a table, each person has their own cup, plate and bowl — three parallel dinner sets, where place setting [3] in each belongs to the same person. If that person moves to a different seat, they take all three of their things with them — you never leave their cup behind while their plate moves.
Sorting parallel arrays works exactly the same way: whenever the sort swaps two items in arrNames, you must swap the same two indexes in arrMarks (and every other parallel array) — so each student keeps their own name and their own mark together.
for i := 1 to Length(arrNames) - 1 do
for j := i + 1 to Length(arrNames) do
if arrNames[i] > arrNames[j] then
begin
// Swap both arrays at the same time
sTemp := arrNames[i]; arrNames[i] := arrNames[j]; arrNames[j] := sTemp;
iTemp := arrMarks[i]; arrMarks[i] := arrMarks[j]; arrMarks[j] := iTemp;
end;Date Methods (Grade 11)
Delphi has built-in functions for working with dates — required for Grade 11 Term 1.
IsLeapYear, YearOf, MonthOf and DayOf live in the DateUtils unit. Add uses DateUtils; near the top of your unit, or Delphi will report "undeclared identifier" when you try to use them.
| Function | Returns | Example & Output |
|---|---|---|
Now | Current date & time (TDateTime) | lblDate.Caption := DateToStr(Now) → '2025/05/30' |
DateToStr(d) | Date as formatted string | DateToStr(dtpBirth.Date) → '2008/03/15' |
TimeToStr(t) | Time as formatted string | TimeToStr(Now) → '14:32:07' |
StrToDate(s) | String → TDateTime | StrToDate('2024/05/01') |
IsLeapYear(y) | Boolean (True/False) | IsLeapYear(2024) → True |
YearOf(d) | Integer year | YearOf(dtpDate.Date) → 2025 |
MonthOf(d) | Integer month (1–12) | MonthOf(Now) → 5 |
DayOf(d) | Integer day (1–31) | DayOf(Now) → 30 |
// Display today's date
lblToday.Caption := DateToStr(Now); // '2025/05/30'
// Calculate age in years
iAge := YearOf(Now) - YearOf(dtpBirth.Date); // e.g. 17
// Check leap year
if IsLeapYear(YearOf(Now)) then
ShowMessage('This is a leap year')
else
ShowMessage('Not a leap year');