Skip to the page
Year 10 Β· Computer Science Β· Summer 1 Β· Programming

Arrays and files; the scenario question

Exam practicePresent β–Ά

What this lesson covers

8.2 Arrays

Cambridge IGCSE Computer Science 0478 Β· Topic 8: Programming Β· Paper 2

8.3 File handling

Cambridge IGCSE Computer Science 0478 Β· Topic 8: Programming Β· Paper 2

7.9 Writing and amending algorithms

Cambridge IGCSE Computer Science 0478 Β· Topic 7: Algorithm design and problem-solving Β· Paper 2

You will learn to

  • Declare and use a 1D array, with a loop and a variable as the index.
  • Use nested loops to work through a 2D array.
  • Write data to a text file, close it, then open it and read the data back.
  • Plan a 15-mark scenario question before writing any code.

Success criteria

  • I can total every score in a 1D array with a loop.
  • I can find an empty seat in a 2D seating plan with nested loops.
  • I can save a list to a file and read it back.
  • I can list the steps my scenario answer needs before I write it.
The syllabus points for these sections
  • Explain what an array is and why it beats many separate variables.
  • Declare and use 1D and 2D arrays, with the first index 0 or 1.
  • Use a variable as an index and a loop to process every element.
  • Use nested loops to work through a 2D array.
  • Explain why programs store data in files.
  • Open a file for READ or WRITE and close it afterwards.
  • Write and read a single item of data.
  • Write and read several lines of text using a loop.
  • Write algorithms precisely, with the exact comparison the problem needs.
  • Amend a given algorithm to do a new job.
  • Plan and answer a 15-mark scenario question.
  • Explain how the scenario question is marked.

Key words

Say each word, then read what it means. Every one is in the glossary too.

Variable
A named place in memory whose value can change while the program runs.
Identifier
The name given to a variable, constant, array or subroutine.
Data type
The kind of value stored: INTEGER, REAL, CHAR, STRING or BOOLEAN.
Selection
Choosing which statements to run using a condition (IF or CASE).
Iteration
Repeating a block of statements in a loop.
Totalling
Adding values into a running total, for example Total ← Total + Value.
Counting
Adding 1 to a counter each time something happens.
Array
A data structure holding many values of the same data type under one name, each found by its index.
Algorithm
A precise, ordered set of steps that solves a problem.
Program development life cycle
The four stages of making a program: analysis, design, coding and testing.
Structure diagram
A top-down diagram that shows how a system is split into sub-systems.
Pseudocode
A structured, code-like way of writing an algorithm that is not tied to one language.
Bubble sort
Sorting by comparing neighbouring items and swapping them if they are in the wrong order, pass after pass.
Validation
An automatic check that input data is reasonable and follows set rules.
Check digit
An extra digit calculated from the other digits, used to catch typing errors.

The explanation

Read it here, or open the study page below to go one step at a time with things to try.

8.2 Arrays

What an array is

An array is a data structure that holds many values of the same data type under one name.

Each value is an element. Each element has a position number called its index.

Without an array, 30 marks need 30 variables. With an array they need one name: `Marks`.

`ARRAY[1:5]` means the first index is 1 and the last is 5. The first index can be 0 or 1, and the exam says which.

Pseudocode index12345
Python index01234
Value5671489065
DECLARE Marks : ARRAY[1:5] OF INTEGER
Marks[1] ← 56
Marks[2] ← 71
Marks[3] ← 48
Marks[4] ← 90
Marks[5] ← 65
OUTPUT Marks[4]
marks = [56, 71, 48, 90, 65]
print(marks[3])
?Why?

One name plus an index means a loop can visit every element. The same few lines work for 5 values or 5000.

!Watch out

Python lists always start at index 0. `marks[3]` in Python is the fourth element, the same one as `Marks[4]` in a pseudocode array that starts at 1.

Using a variable as the index

The index can be a variable. `Marks[Count]` means the element whose index is the value in Count.

Put that inside a FOR loop, and the loop visits every element in turn.

e.g.Example
Marks typed: 56, 71, 48, 90, 65 Total = 56 + 71 + 48 + 90 + 65 = 330 Highest starts at 56. 71 > 56, so 71. 48 is not bigger. 90 > 71, so 90. 65 is not bigger. Output: Total: 330 and Highest: 90
DECLARE Marks : ARRAY[1:5] OF INTEGER
DECLARE Count : INTEGER
DECLARE Total : INTEGER
DECLARE Highest : INTEGER
FOR Count ← 1 TO 5
  OUTPUT "Enter mark ", Count
  INPUT Marks[Count]
NEXT Count
Total ← 0
Highest ← Marks[1]
FOR Count ← 1 TO 5
  Total ← Total + Marks[Count]
  IF Marks[Count] > Highest
    THEN
      Highest ← Marks[Count]
  ENDIF
NEXT Count
OUTPUT "Total: ", Total
OUTPUT "Highest: ", Highest
marks = [0] * 5
for count in range(5):
    marks[count] = int(input("Enter mark " + str(count + 1) + ": "))
total = 0
highest = marks[0]
for count in range(5):
    total = total + marks[count]
    if marks[count] > highest:
        highest = marks[count]
print("Total:", total)
print("Highest:", highest)
?Why?

Highest starts at the first element, not at 0. If every value were negative, starting at 0 would give the wrong answer.

2D arrays: rows and columns

A 2D array is a table of values with rows and columns. Every element has the same data type.

`ARRAY[1:3, 1:4]` has 3 rows and 4 columns, so 3 Γ— 4 = 12 elements.

You give two indexes: row first, then column. `Scores[2, 3]` is row 2, column 3.

Try the toy: tap a cell to read its address and value, then type a new value in Change the value. Then press Step to run the nested loop total. The toy uses different marks from the table below, so its Scores[2, 3] holds 16.

ScoresColumn 1Column 2Column 3Column 4
Row 1 (Ana)7596
Row 2 (Ben)8649
Row 3 (Carla)5978
e.g.Example
Scores[2, 3] is row 2 (Ben), column 3 β†’ 4. After Scores[2, 3] ← 10, Ben's third test is 10. Output: 4, then 10
DECLARE Scores : ARRAY[1:3, 1:4] OF INTEGER
// (Scores holds the values in the table)
OUTPUT Scores[2, 3]
Scores[2, 3] ← 10
OUTPUT Scores[2, 3]
scores = [[7, 5, 9, 6],
          [8, 6, 4, 9],
          [5, 9, 7, 8]]
print(scores[1][2])
scores[1][2] = 10
print(scores[1][2])
!Watch out

Row first, then column. In Python each row is its own list, so you write `scores[row][column]` with two pairs of brackets, and both start at 0.

There is something to try for this step in the IGCSE library.

Nested loops to visit every element

To visit every element of a 2D array, use a nested loop: one loop inside another.

The outer loop goes through the rows. The inner loop goes through the columns of the current row.

The inner loop does all its passes for each single pass of the outer loop. Here that is 3 Γ— 4 = 12 passes in total.

e.g.Example
Row 1: 7 + 5 + 9 + 6 = 27 Row 2: 8 + 6 + 4 + 9 = 27 Row 3: 5 + 9 + 7 + 8 = 29 Grand total: 27 + 27 + 29 = 83
DECLARE Scores : ARRAY[1:3, 1:4] OF INTEGER
DECLARE Row : INTEGER
DECLARE Column : INTEGER
DECLARE RowTotal : INTEGER
DECLARE GrandTotal : INTEGER
// (Scores holds the values in the table above)
GrandTotal ← 0
FOR Row ← 1 TO 3
  RowTotal ← 0
  FOR Column ← 1 TO 4
    RowTotal ← RowTotal + Scores[Row, Column]
  NEXT Column
  OUTPUT "Row ", Row, " total: ", RowTotal
  GrandTotal ← GrandTotal + RowTotal
NEXT Row
OUTPUT "Grand total: ", GrandTotal
scores = [[7, 5, 9, 6],
          [8, 6, 4, 9],
          [5, 9, 7, 8]]
grand_total = 0
for row in range(3):
    row_total = 0
    for column in range(4):
        row_total = row_total + scores[row][column]
    print("Row", row + 1, "total:", row_total)
    grand_total = grand_total + row_total
print("Grand total:", grand_total)
!Watch out

Set RowTotal to 0 inside the outer loop but before the inner loop. In any other place, totals carry over from one row to the next, or reset too often.

Initialising a 2D array

Initialising means giving every element a starting value before the array is used.

A nested loop can set every element. Here a cinema has 5 rows of 8 seats. FALSE means the seat is free.

e.g.Example
5 rows Γ— 8 seats = 40 elements, all set to FALSE. Booking row 2, seat 5 sets that one element to TRUE. Output: TRUE FALSE (Python shows True False)
DECLARE Seats : ARRAY[1:5, 1:8] OF BOOLEAN
DECLARE Row : INTEGER
DECLARE Seat : INTEGER
FOR Row ← 1 TO 5
  FOR Seat ← 1 TO 8
    Seats[Row, Seat] ← FALSE
  NEXT Seat
NEXT Row
Seats[2, 5] ← TRUE    // book row 2, seat 5
OUTPUT Seats[2, 5], " ", Seats[1, 1]
seats = [[False] * 8 for row in range(5)]
seats[1][4] = True    # book row 2, seat 5
print(seats[1][4], seats[0][0])
!Watch out

In Python, do not write `[[False] * 8] * 5`. That makes five copies of the same row, so booking one seat books it in every row.

8.3 File handling

Why programs store data in files

Variables and arrays are held in RAM. When the program ends, or the power goes off, that data is lost.

A file is kept on secondary storage, such as an SSD. The data stays there after the program stops.

Files let a program save data now and load it next time, such as a high-score table or a class register.

Files also move data between programs: one program writes the file and another reads it.

?Why?

Without files, a game would forget your high score each time you closed it. A school would retype the register every morning.

Open, read or write, close

Every file task follows the same pattern: open the file, read or write, then close it.

`OPENFILE "Scores.txt" FOR WRITE` creates the file. If it already exists, its old contents are wiped.

`OPENFILE "Scores.txt" FOR READ` opens an existing file so the program can read it from the first line.

`CLOSEFILE` finishes the job: the data is saved properly and the file is free for other programs.

PseudocodePythonWhat it does
OPENFILE "Scores.txt" FOR READf = open("Scores.txt", "r")Open to read from the start
OPENFILE "Scores.txt" FOR WRITEf = open("Scores.txt", "w")Create, or empty, the file to write to
READFILE "Scores.txt", Lineline = f.readline()Read the next line into a variable
WRITEFILE "Scores.txt", Linef.write(line + "\n")Write one line to the file
CLOSEFILE "Scores.txt"f.close()Close the file
!Watch out

If you forget to close a file, the data may never reach the disk. Python also has an append mode, `"a"`, which adds to the end of a file. That is extra: the 0478 syllabus only needs READ and WRITE.

Writing and reading a single item

A single item is one value, such as a high score.

WRITEFILE writes one line. READFILE reads one line into a variable.

In Python, `f.write()` needs a string, so use `str()`. A line read back is a string ending in a new-line character. `.strip()` removes it, then `int()` makes a number.

e.g.Example
HighScore.txt after writing holds one line: 2450 The program reads it back into HighScore. Output: Best score: 2450
DECLARE HighScore : INTEGER
HighScore ← 2450
OPENFILE "HighScore.txt" FOR WRITE
WRITEFILE "HighScore.txt", HighScore
CLOSEFILE "HighScore.txt"

OPENFILE "HighScore.txt" FOR READ
READFILE "HighScore.txt", HighScore
CLOSEFILE "HighScore.txt"
OUTPUT "Best score: ", HighScore
high_score = 2450
f = open("HighScore.txt", "w")
f.write(str(high_score) + "\n")
f.close()

f = open("HighScore.txt", "r")
high_score = int(f.readline().strip())
f.close()
print("Best score:", high_score)

Writing and reading lines of text with a loop

Each READFILE reads the next line. The file keeps track of where it got to.

To write many lines, put WRITEFILE inside a loop. To read them back, put READFILE inside a loop and store each line in an array element.

e.g.Example
Register.txt after writing: Ana Ben Carla Output after reading: 1: Ana 2: Ben 3: Carla
DECLARE Names : ARRAY[1:3] OF STRING
DECLARE Count : INTEGER
Names[1] ← "Ana"
Names[2] ← "Ben"
Names[3] ← "Carla"

OPENFILE "Register.txt" FOR WRITE
FOR Count ← 1 TO 3
  WRITEFILE "Register.txt", Names[Count]
NEXT Count
CLOSEFILE "Register.txt"

OPENFILE "Register.txt" FOR READ
FOR Count ← 1 TO 3
  READFILE "Register.txt", Names[Count]
  OUTPUT Count, ": ", Names[Count]
NEXT Count
CLOSEFILE "Register.txt"
names = ["Ana", "Ben", "Carla"]

f = open("Register.txt", "w")
for count in range(3):
    f.write(names[count] + "\n")
f.close()

f = open("Register.txt", "r")
for count in range(3):
    names[count] = f.readline().strip()
    print(str(count + 1) + ": " + names[count])
f.close()
!Watch out

Opening the file FOR WRITE a second time would wipe the three names. Open it FOR READ when you only want to look at the data.

7.9 Writing and amending algorithms

Be precise, and amend with care

An algorithm must say exactly what to do. 'More than 50' is `> 50`. '50 or more' is `>= 50`. These give different results for 50.

Set every total, counter, highest and lowest to a start value before the loop. Use meaningful names like `PassCount`, not `x`, and `//` comments.

An amend question asks you to change a given algorithm. Find the line that controls the behaviour and change only that line.

Example: to make the bubble sort give descending order (largest first), change `>` to `<` in the comparison.

Words in the questionPseudocode
over 18 / more than 18`Age > 18`
18 or over / at least 18`Age >= 18`
under 18 / less than 18`Age < 18`
between 1 and 21 inclusive`Days >= 1 AND Days <= 21`
not equal to -1`Value <> -1`
e.g.Example
7, 3, 9, 2, 5 sorted with the amended line: Output: 9, 7, 5, 3, 2
// Original: sorts into ascending order (smallest first)
IF Numbers[Index] > Numbers[Index + 1]

// Amended: sorts into descending order (largest first)
IF Numbers[Index] < Numbers[Index + 1]
numbers = [7, 3, 9, 2, 5]
top = 5
swap = True
while swap == True and top > 1:
    swap = False
    for index in range(top - 1):
        # amended: < instead of > gives descending order
        if numbers[index] < numbers[index + 1]:
            temp = numbers[index]
            numbers[index] = numbers[index + 1]
            numbers[index + 1] = temp
            swap = True
    top = top - 1
print(numbers)
?Why?

Rewriting the whole algorithm wastes time and can add new errors. The examiner is looking for the one or two key changes.

!Watch out

`Days >= 1 AND <= 21` is wrong. Write the variable on both sides: `Days >= 1 AND Days <= 21`.

The 15-mark scenario question: plan first

The last question on Paper 2 is a scenario worth 15 marks. Allow about 30 minutes. You may answer in pseudocode, Python, Visual Basic or Java.

Read the scenario twice. Underline every task. Make a numbered checklist and tick each item as you code it.

Sample scenario: a teacher records three tests for each of 30 students. Each test is out of 50. Names are already in `StudentName[1:30]`.

e.g.Example
Tasks in the sample scenario: 1. Input three marks per student and store them in StudentMark[1:30, 1:3]. 2. Validate each mark: 0 to 50. 3. Calculate and store each student's total in StudentTotal[1:30]. 4. Calculate each student's average, rounded to 1 decimal place. 5. Output each name with total and average. 6. Count and output the students with a total of 120 or more (a merit). 7. Output the class average total and the name of the student with the highest total. All inputs and outputs need suitable messages.
?Why?

Marks are given for meeting each requirement. A checklist stops you forgetting one, which is the most common way to lose marks here.

Model answer in pseudocode and Python

The model answer uses two nested `FOR` loops: one for students, one for tests. It reuses validation, totalling, counting, maximum and average.

Read the comments. They say what each part does, which also earns marks.

Python lists start at index 0, so the Python loops use `range(30)` and `range(3)`.

The first Python line is a stand-in for the names, so the program can run. In the exam you do not write it, because the names are already stored.

e.g.Example
If one student scores 45, 40 and 38: Total = 45 + 40 + 38 = 123. Average = 123 Γ· 3 = 41.0 123 >= 120, so MeritCount goes up by 1. If 123 is more than TopTotal, TopTotal becomes 123 and TopStudent becomes this student's index. Python sample run: Enter mark for test 1 for Student 1: 55 Error: a mark must be from 0 to 50. Enter it again: 31
// StudentName[1:30] already holds the 30 names
DECLARE StudentName : ARRAY[1:30] OF STRING
DECLARE StudentMark : ARRAY[1:30, 1:3] OF INTEGER
DECLARE StudentTotal : ARRAY[1:30] OF INTEGER
DECLARE Student : INTEGER
DECLARE Test : INTEGER
DECLARE Mark : INTEGER
DECLARE Total : INTEGER
DECLARE Average : REAL
DECLARE ClassTotal : INTEGER
DECLARE MeritCount : INTEGER
DECLARE TopTotal : INTEGER
DECLARE TopStudent : INTEGER

// set the class totals and counters to their start values
ClassTotal ← 0
MeritCount ← 0
TopTotal ← -1
TopStudent ← 1

FOR Student ← 1 TO 30
  Total ← 0
  FOR Test ← 1 TO 3
    // input one mark and validate it with a range check (0 to 50)
    OUTPUT "Enter mark for test ", Test, " for ", StudentName[Student]
    INPUT Mark
    WHILE Mark < 0 OR Mark > 50 DO
      OUTPUT "Error: a mark must be from 0 to 50. Enter it again"
      INPUT Mark
    ENDWHILE
    // store the valid mark and add it to this student's total
    StudentMark[Student, Test] ← Mark
    Total ← Total + Mark
  NEXT Test
  // store the total, work out the average and output the results
  StudentTotal[Student] ← Total
  Average ← ROUND(Total / 3, 1)
  OUTPUT StudentName[Student], " Total: ", Total, " Average: ", Average
  ClassTotal ← ClassTotal + Total
  // a total of 120 or more earns a merit
  IF Total >= 120
    THEN
      MeritCount ← MeritCount + 1
  ENDIF
  // remember the highest total so far and whose it is
  IF Total > TopTotal
    THEN
      TopTotal ← Total
      TopStudent ← Student
  ENDIF
NEXT Student

// whole-class results
OUTPUT "Class average total: ", ROUND(ClassTotal / 30, 1)
OUTPUT "Number of merits: ", MeritCount
OUTPUT "Highest total: ", StudentName[TopStudent], " with ", TopTotal
# The question says the names are already stored.
# This line is a stand-in so the program can run.
student_name = ["Student " + str(n) for n in range(1, 31)]
student_mark = [[0, 0, 0] for row in range(30)]
student_total = [0] * 30

# set the class totals and counters to their start values
class_total = 0
merit_count = 0
top_total = -1
top_student = 0

for student in range(30):
    total = 0
    for test in range(3):
        # input one mark and validate it with a range check (0 to 50)
        mark = int(input("Enter mark for test " + str(test + 1) + " for " + student_name[student] + ": "))
        while mark < 0 or mark > 50:
            mark = int(input("Error: a mark must be from 0 to 50. Enter it again: "))
        # store the valid mark and add it to this student's total
        student_mark[student][test] = mark
        total = total + mark
    # store the total, work out the average and output the results
    student_total[student] = total
    average = round(total / 3, 1)
    print(student_name[student], "Total:", total, "Average:", average)
    class_total = class_total + total
    # a total of 120 or more earns a merit
    if total >= 120:
        merit_count = merit_count + 1
    # remember the highest total so far and whose it is
    if total > top_total:
        top_total = total
        top_student = student

# whole-class results
print("Class average total:", round(class_total / 30, 1))
print("Number of merits:", merit_count)
print("Highest total:", student_name[top_student], "with", top_total)
?Why?

The Python version was run with 90 test marks, including invalid ones, to check it works. In Python, `round(total / 3, 1)` keeps one decimal place; `//` would cut off the decimals.

!Watch out

Store values in the arrays the question names. Calculating the total but not storing it in StudentTotal loses marks.

How the 15 marks are awarded

Recent mark schemes use levels, not one mark per line. AO2 (applying techniques and data structures) gives up to 9 marks. AO3 (comments, identifiers, logic and accuracy) gives up to 6 marks.

The examiner reads the whole answer and picks the band that fits best. Minor syntax errors are ignored if the logic is clear.

BandAO2: techniques and data structures (9)AO3: comments, names, accuracy (6)
Top7–9: all tasks covered with the right techniques; arrays store all the data5–6: fully commented, meaningful names, logical and accurate, meets all requirements
Middle4–6: some techniques suit the problem; some data stored correctly3–4: some comments, most names sensible, most requirements attempted
Low1–3: at least one technique used; some data stored, not well1–2: no useful comments, some sensible names, at least one requirement attempted
e.g.Example
The model answer reaches the top bands because it: - inputs with messages and validates every mark (input, iteration, selection) - stores marks in the 2D array and totals in StudentTotal (data structures) - uses totalling, counting, maximum, average and ROUND - outputs every result with a message - has a comment for every section and meaningful names like MeritCount
?Why?

Because marks come in bands, a working answer to every task beats a perfect answer to half of them. Attempt every requirement, even if one part is rough.

Study it

Open the study page and go one step at a time.

Check yourself

One question at a time. The reason shows after each answer.

Saved on this device.