AS & A Level Computer Science · Area 1 · AS Level content

Programming basics, constructs and structured programming

This section is examined by asking you to write pseudocode, not to describe it, so every mark depends on the exact keywords and on the order of the statements. Declarations and constants are marked almost mechanically, and those are the easiest marks in the paper to throw away. The constructs carry the most marks, and they are lost in predictable ways: an UNTIL clause that states when to carry on rather than when to stop, a loop whose counter is never changed, a missing ENDIF, or an ELSE attached to the wrong IF. Procedures and functions are marked on whether the value comes back through RETURN, and on whether you passed by reference only when the caller's variable really has to change.

Not started

Syllabus coverage

  • Implement and write pseudocode from a given design presented as either a program flowchart or structured English
  • Write pseudocode statements for the declaration and initialisation of constants
  • Write pseudocode statements for the declaration of variables and the assignment of values to variables
  • Write pseudocode statements for expressions involving any of the arithmetic or logical operators
  • Write pseudocode statements for input from the keyboard and output to the console
  • Use built-in functions and library routines; any function not given in the pseudocode guide will be provided, and string manipulation functions will always be given
  • Use pseudocode to write an IF statement including the ELSE clause, and nested IF statements
  • Use pseudocode to write a CASE structure
  • Use pseudocode to write a count-controlled loop, a post-condition loop and a pre-condition loop
  • Justify why one loop structure may be better suited to solve a problem than the others
  • Define and use a procedure, and explain where in the construction of an algorithm it is appropriate to use one
  • Use parameters, of which a procedure may have none, one or more, passed by reference or by value
  • Define and use a function, and explain where it is appropriate to use one; a function is used in an expression and its return value replaces the call
  • Use the terminology of procedures and functions - header, interface, parameter, argument, return value - and write efficient pseudocode

Part of the AS & A Level Computer Science syllabus 9618.

Declaring constants and variables

Every value a program works with has to be given a name and a place to live before it is used. A variable is a named storage location whose value can change while the program runs; a constant is a named storage location whose value is fixed at the moment it is declared and cannot be changed afterwards. The declaration is a statement of intent to whoever reads the program: this name exists, it holds this kind of data, and nothing else may be stored in it.

A variable is declared with DECLARE, followed by the identifier, a colon and a data type, for example DECLARE TotalScore : INTEGER. The type decides which operations are legal and which are not, so a total that will hold marks is INTEGER or REAL, a name is STRING, a grade letter is CHAR and a flag is BOOLEAN. Declaring a variable does not give it a value. An uninitialised variable holds whatever happened to be in that memory before, so anything that is going to be added to or counted must be set to 0 first, and anything that is going to be joined to must be set to the empty string.

A constant is declared with CONSTANT, the identifier, an equals sign and a value, for example CONSTANT VATRate = 0.2. There is no data type in the declaration because the type comes from the value itself: 0.2 makes it REAL, and "N/A" makes it STRING. Only a literal may follow the equals sign. A variable, another constant or an expression is not allowed, because the value has to be fixed at the point of declaration and must not depend on anything that happens later.

Constants are worth using for three reasons, and the third is the one that earns marks. A name such as VATRate says what the number means, whereas 0.2 says nothing. If the rate changes it is changed in one place, not in every expression that used the literal. And a constant cannot be overwritten by accident in the middle of a long program, which is exactly the bug that a variable used as a constant invites.

  • Constant: CONSTANT Identifier = literal - CONSTANT VATRate = 0.2, CONSTANT MaxSize = 100, CONSTANT DefaultText = "N/A".
  • Variable: DECLARE Identifier : data type - DECLARE TotalScore : INTEGER, DECLARE Average : REAL, DECLARE Finished : BOOLEAN.
  • Declarations go at the top of the module, before the first statement that uses the name.
  • Initialise accumulators and counters to 0 before the loop that changes them: Total <- 0, Count <- 0.
  • A constant is never on the left of an assignment arrow. If the value can change, it was a variable and should have been declared as one.
StatementWhat it doesWhat it does not do
DECLARE Mark : INTEGERReserves a storage location, names it Mark and fixes its type as a whole numberIt does not give Mark a value, so Mark cannot be added to anything yet
Mark <- 0Assigns the value 0 to an existing variableIt does not declare anything - the variable must already exist
CONSTANT PassMark = 40Declares a constant and initialises it in the same statement, with a literalIt cannot be given a variable or an expression, and it cannot be reassigned later
A constant is not simply a variable you promise not to change. It is declared with a different keyword, it cannot be assigned to at all, and its value must be a literal - so CONSTANT Rate = BaseRate * 2 is wrong before the logic is even considered.

Assignment and arithmetic expressions

The assignment operator is the left arrow, written <- in plain text. The statement Total <- Total + 1 means take the current value of Total, add one to it, and store the result back in Total; it is not an equation and it is not claiming that a number equals itself plus one. Whatever is on the right is evaluated first, using the values the variables hold at that moment, and only then is the result stored on the left, so a swap needs a third variable to hold one value while the other is overwritten.

The left of the arrow must be a single storage location: a variable, an array element such as Scores[3], or a field such as Pupil.YearGroup. The right may be any expression whose value is of the same type. A statement that puts an expression on the left, such as Total + 1 <- Total, is not pseudocode at all.

The arithmetic operators are +, -, *, /, DIV and MOD. Division with / always gives a REAL, even when both operands are integers, so 7 / 2 is 3.5 and not 3. DIV gives the whole-number quotient and MOD gives the remainder, which is what makes them useful: 7 DIV 2 is 3, 7 MOD 2 is 1, and Number MOD 2 = 0 is the standard test for an even number. Multiplication and division are carried out before addition and subtraction, and brackets are used whenever the order matters or is not obvious to a reader.

Keep the types straight, because an expression that mixes them is where the logic quietly goes wrong. Adding an INTEGER to a REAL gives a REAL, which is why an average has to be declared REAL rather than INTEGER, and dividing a total of marks by a count of students with / gives the exact average, while DIV throws away the fraction and understates it.

OperatorMeaningExampleResult
+AdditionTotal <- Total + MarkThe mark is added to the running total
-SubtractionBalance <- Balance - FeeThe fee is taken off the balance
*MultiplicationPay <- Hours * HourlyRateHours multiplied by the rate
/Division, always REALShare <- 7 / 23.5, even though both operands are integers
DIVInteger division, the quotientWhole <- 7 DIV 23
MODModulus, the remainderLeft <- 7 MOD 21
=Comparison, not assignmentIF Answer = "Y" THENTRUE or FALSE, used in a condition
Using = where you meant <- is the single most common error in this topic. <- stores a value; = asks whether two values are the same and returns TRUE or FALSE, so it belongs in a condition and never on its own as a statement.

Input, output and the sequence of statements

INPUT reads a value from the keyboard into a variable that has already been declared, and OUTPUT sends values to the console. The form is INPUT Identifier and OUTPUT value, or several values separated by commas, as in OUTPUT "You have ", Lives, " lives left". A value in quotation marks is printed exactly as it stands; anything else is evaluated and its value is printed in its place.

INPUT is a statement, not a function, so it does not return a value that can be used inside an expression: you cannot write Total <- Total + INPUT Mark. Read into a variable first, then use the variable. What the user types is converted to the declared type of that variable, which is why the declaration has to be right before the read, not afterwards.

The order of the statements is the logic. Declarations come first, then the values that have to be set before processing, then the processing, then the output. A total printed before the loop that calculates it prints zero, and a variable read after it has been used has not been read at all - both are sequence errors, and both are marked wrong even when every individual statement is correct.

A whole small program is therefore four steps: declare, initialise, process, output. That shape is worth writing even when the question only asks for part of it, because it keeps you from leaving out the initialisation, which is usually worth a mark on its own.

Most questions of this kind start from a design rather than from nothing. A program flowchart translates one symbol at a time: a parallelogram becomes INPUT or OUTPUT, a rectangle becomes an assignment, a diamond becomes the condition of an IF or a loop, and each arrow becomes the next statement in sequence. Structured English translates even more directly, because its numbered or indented steps are already statements in order, and the words it uses - read, set, add, display - map onto INPUT, assignment, calculation and OUTPUT. In both cases the identifiers in the design become the declared variables, so the declarations you write at the top are the names the design already uses, with the type each one needs.

PseudocodePurpose
CONSTANT VATRate = 0.2Declares the constant once, with a literal
DECLARE Price : REALDeclares a variable of the right type for money
DECLARE Total : REALDeclares the variable that will hold the answer
INPUT PriceReads the price typed at the keyboard into Price
Total <- Price + Price * VATRateCalculates the total, using the constant rather than a literal
OUTPUT "Total including VAT: ", TotalPrints a label and the value
If a question says the program must keep asking until the input is acceptable, INPUT belongs inside the loop, not before it - and the loop is a post-condition loop, which is the next topic but one.

Built-in functions and library routines

A built-in function is supplied with the language and needs no definition: you write its name, give it its arguments in brackets, and it hands back a value. A library routine is a procedure or function supplied in a library that the program has to make available, such as a maths library or a file-handling library. The difference that matters in an exam is small and practical: a built-in is always there, a library routine has to be brought in, and both save you from writing and testing code that already exists.

Each function has a fixed signature: the number of arguments, their types, their order and the type of the value returned. LENGTH takes one STRING and returns an INTEGER, so LENGTH("Happy Days") is 10. RIGHT takes a STRING and an INTEGER and returns a STRING, so RIGHT("ABCDEFGH", 3) is "FGH". MID takes a STRING, a start position and a length, so MID("ABCDEFGH", 2, 3) is "BCD". INT takes a REAL and returns its whole-number part, truncating rather than rounding, so INT(27.5415) is 27 and INT(27.9) is also 27.

RAND is worth learning exactly, because it is the one students misremember. RAND(x) returns a random REAL from 0 up to but not including x, so RAND(87) might return 35.43. To get a whole number from 1 to 6 you therefore write INT(RAND(6)) + 1: the RAND gives 0 up to 5.999..., the INT cuts it to 0 to 5, and the +1 shifts it to 1 to 6.

Two rules follow for the exam. A function that returns a value belongs in an expression, not on a line of its own, so the value it produces is actually used. And you are not expected to remember functions that are not in the pseudocode guide: any function you are given will be defined in the question, and string manipulation functions are always given, so read the signature and use it in the order and with the types shown.

FunctionArgumentsReturnsExample
LENGTH(ThisString)one STRINGINTEGERLENGTH("Happy Days") returns 10
RIGHT(ThisString, x)STRING, INTEGERSTRINGRIGHT("ABCDEFGH", 3) returns "FGH"
MID(ThisString, x, y)STRING, INTEGER, INTEGERSTRINGMID("ABCDEFGH", 2, 3) returns "BCD"
LCASE(ThisChar), UCASE(ThisChar)one CHARCHARUCASE('h') returns 'H'
INT(x)one REALINTEGERINT(27.5415) returns 27
RAND(x)one INTEGERREALRAND(87) may return 35.43; the range is 0 up to but not including 87
Read the signature before you use it. If the question defines RIGHT(ThisString, x), then RIGHT(3, "ABCDEFGH") has the arguments the wrong way round, and the mark is lost even though the idea was right.

Selection: IF, ELSE and nested IF

An IF statement runs a group of statements only when a condition is TRUE. The condition must evaluate to a BOOLEAN, the statements that depend on it sit between THEN and ENDIF, and an optional ELSE introduces the statements that run when the condition is FALSE. ENDIF is not decoration: it marks where the two branches join again, and every IF needs one.

A one-way IF has no ELSE, and that is correct when there is nothing to do if the condition fails. A two-way IF has an ELSE, and it is the right choice when exactly one of two things must happen, such as a pass or a fail, a discount or no discount. The statements after ENDIF run whatever happened inside, which is what makes selection a construct rather than a jump.

A nested IF is an IF placed inside another IF, and it is needed when the second question only makes sense after the first has been answered. Deciding a grade band is the standard case: first ask whether the mark is at least 80, and only if it is not, ask whether it is at least 70. Putting the second test inside the ELSE of the first is what makes the bands mutually exclusive.

Indentation is not marked, but it is how you keep the structure right, because each ELSE belongs to the nearest IF above it that has not yet been closed. If you have three IFs you must have three ENDIFs, and a missing one changes the meaning of the whole block even though the logic still reads plausibly. When the nesting goes deeper than two or three levels, or when the same variable is being tested against a list of values, the structure you actually want is a CASE.

  • One-way: IF Mark >= PassMark THEN OUTPUT "Pass" ENDIF
  • Two-way: IF Mark >= PassMark THEN OUTPUT "Pass" ELSE OUTPUT "Fail" ENDIF
  • Nested: IF Mark >= 80 THEN Grade <- 'A' ELSE IF Mark >= 70 THEN Grade <- 'B' ELSE Grade <- 'C' ENDIF ENDIF
  • Conditions are built from =, <>, >, <, >= and <=, combined with AND, OR and NOT, with brackets to make the order explicit.
  • Every IF needs its own ENDIF, and the ELSE belongs to the nearest unclosed IF.
The mistake examiners see most often is not a wrong condition - it is odd numbers of ENDIFs. If you write a nested IF, count the IFs and the ENDIFs before you move on.

Selection: the CASE structure

A CASE structure chooses one branch from several by testing a single identifier against a list of values. The form is CASE OF Identifier, then each value followed by a colon and its statements, then ENDCASE. Each value may also be a range written value1 TO value2, so 70 TO 79 : Grade <- 'B' is one clause and not nine.

Two rules explain almost every CASE question. The clauses are tested in sequence, and the first one that applies is executed and the rest are skipped, so control passes to the statement after ENDCASE - the cases do not all run. And an OTHERWISE clause, if there is one, must be last: it runs when none of the values or ranges above it matched, which is what stops an unexpected value falling through with no branch at all.

A CASE tests one variable against fixed values or ranges. It cannot test two different variables, and it cannot test a compound condition such as Total > 100 AND Member = TRUE. If a clause needs AND or OR, the structure you want is an IF. Conversely, if your nested IF tests the same identifier five times against five values, the structure you want is a CASE, because the reader can see all five branches at once and cannot lose track of the ENDIFs.

The natural uses are menus, where a single character chooses an option, grade bands, where the ranges are fixed, and any state that moves through a known set of named states. In each of those, a CASE says in one screen what six nested IFs would say in twenty lines.

QuestionNested IFCASE
What is testedAny condition, including compound conditions on different variablesOne identifier, against a fixed value or a range of values
How many branchesTwo per IF, so five outcomes need five IFs nestedAs many clauses as you like, one per value or range
ReadabilityDeep nesting hides the logic and invites a missing ENDIFAll the branches are visible in one column, and one ENDCASE closes them
Use it whenEach test depends on the result of the one before, or the conditions are ranges combined with AND or ORA single value or range selects the branch - menus, grade bands, states
If a CASE clause contains AND or OR, you want an IF. If a nested IF repeats the same identifier against a list of values, you want a CASE. Examiners set questions that turn on exactly that choice.

Count-controlled loops: FOR

A count-controlled loop repeats a group of statements a known number of times. It is written FOR Identifier <- value1 TO value2, then the statements, then NEXT Identifier, with an optional STEP increment. The counter must be an INTEGER, and both bounds must be expressions that evaluate to integers.

The counter is assigned each value from value1 to value2 inclusive, and the statements run after each assignment, so FOR Index <- 1 TO 5 runs five times with Index equal to 1, 2, 3, 4 and 5. Two boundary cases are worth knowing: if value1 = value2 the body runs once, and if value1 > value2 with a positive step the body does not run at all. STEP changes the interval, so FOR Index <- 10 TO 1 STEP -1 counts down and FOR Index <- 2 TO 10 STEP 2 visits 2, 4, 6, 8 and 10.

Use it whenever the number of repetitions is settled before the loop starts: every element of an array, twelve months, thirty students, three attempts. The bounds should come from the data where possible, so a loop over ARRAY[1:30] runs FOR Index <- 1 TO 30 and cannot overrun by one.

Do not assign to the counter inside the body - the NEXT statement is what moves it on, and changing it by hand makes the number of repetitions unpredictable. In nested loops the inner loop finishes all of its repetitions for each single repetition of the outer loop, and repeating the identifier after NEXT is what keeps the two ends matched, especially when the loops are three deep.

  • FOR Index <- 1 TO 10 ... NEXT Index - ten repetitions, Index from 1 to 10.
  • FOR Index <- 0 TO 9 ... NEXT Index - ten repetitions, for an array with a lower bound of 0.
  • FOR Index <- 10 TO 1 STEP -1 ... NEXT Index - ten repetitions, counting down.
  • FOR Row <- 1 TO 5 FOR Column <- 1 TO 3 ... NEXT Column NEXT Row - a 2D array, inner loop inside the outer.
  • The count is known before the first repetition. If it is not, this is the wrong loop.
A FOR loop cannot wait for something to happen. If the number of repetitions depends on what the user types, on a sentinel value or on reaching the end of a file, the loop you want is a WHILE or a REPEAT.

Post-condition and pre-condition loops, and choosing between them

A post-condition loop is written REPEAT, then the statements, then UNTIL condition. The body runs first and the condition is tested afterwards, so the body always runs at least once. The condition is the exit condition: the loop repeats while the condition is FALSE and stops the moment it becomes TRUE. UNTIL Answer = "Y" means keep going until the answer is Y, so a user who types N is asked again.

A pre-condition loop is written WHILE condition, then the statements, then ENDWHILE. The condition is tested first, so the body may run zero times. This condition is the continuation condition: the loop carries on while it is TRUE and stops when it becomes FALSE. The two loops can do the same job with opposite-looking conditions, which is why converting between them means negating the condition as well as moving the test.

Choose by asking two questions. Is the number of repetitions known before the loop starts? If yes, use FOR. If no, does the body have to run at least once? A validation loop must run at least once, because there is no value to test until something has been read, so it is a REPEAT. A loop that reads records from a file, or searches a list that may be empty, must be allowed to run zero times, because the test can be made before anything is read, so it is a WHILE.

Every loop needs a way out. Whatever variable appears in the condition must be changed somewhere inside the body, or the condition can never change and the loop runs for ever; and the change must move the variable towards the exit, which is why a counter that is incremented when it should be decremented produces an infinite loop rather than a wrong answer.

LoopFormCondition testedLeast runsUse when
Count-controlledFOR Index <- 1 TO 10 ... NEXT IndexAgainst the bounds, before each repetition0, if the start is past the endThe number of repetitions is known before the loop starts
Post-conditionREPEAT ... UNTIL conditionAfter the body; TRUE stops the loop1The body must run at least once - validating input, showing a menu
Pre-conditionWHILE condition ... ENDWHILEBefore the body; FALSE stops the loop0The body may need to run zero times - reading a file, searching a list
REPEAT ... UNTIL Valid = TRUE and WHILE NOT Valid ... ENDWHILE do the same job with opposite conditions. One states when to stop, the other states when to carry on, and mixing the two is the most expensive error in this section.

Structured programming: procedures, functions and parameters

A procedure is a named block of statements that carries out one task and is called with CALL. The definition runs from PROCEDURE Name(parameters) to ENDPROCEDURE, and calling it is a complete statement: CALL PrintHeading(). A procedure is used when a group of statements would otherwise be written more than once, or when one identifiable step of the decomposition deserves a name of its own. It keeps the code in one place, so a correction is made once and applies to every call, it shortens the main program to something a reader can follow, and it can be tested on its own with chosen values.

A function is the same idea with one difference that changes how it is used: it returns exactly one value. The header states the type with RETURNS, the body supplies the value with RETURN, and the call is not a statement of its own but part of an expression, where the returned value takes the place of the call. That is why a function call never takes CALL and never sits alone on a line: OUTPUT Max(10, Distance * 2) works because the value slots into the expression, and CALL Max(10, 20) is wrong.

Use a function when the answer is a single value that is needed inside a calculation or a condition - a tax due, the larger of two numbers, the next free position in an array - because the call can then be dropped straight into an expression. If the module has to give back two things, such as a new total and a new count, it is a procedure with those two values passed by reference, because a function can only return one.

The terminology is marked directly. The header is the first line of the definition: PROCEDURE Name(Size : INTEGER). The interface is what the header tells a caller - the name, the parameters and their types, and the return type - and it is all the caller needs to know, because the body is hidden behind it. A parameter is the identifier in the definition; an argument is the actual value supplied in the call; the return value is what the function hands back.

Parameters are passed by value or by reference. By value, the parameter is a copy, so anything the module does to it is lost when the module ends and the caller's variable is untouched. By reference, the parameter is the caller's own variable, so a change inside the module is a change in the caller. In 9618 the keyword BYREF or BYVAL precedes the parameter in the header, and passing by value is assumed when neither is written. Pass by value when the module only needs the value, because it protects the caller's data from accidental change; pass by reference when the module must give something back, as in a swap or a running total, because that is the only way a procedure can change the caller's variables. Parameters should not be passed by reference to a function.

Efficient pseudocode is the last requirement, and it is judged on plain things: no duplicated blocks, one task per module, meaningful identifiers, every variable declared, only the parameters a module actually needs, and indentation that shows which statements belong to which construct. A program that computes the same total in three places is not efficient, however fast it runs.

FeatureProcedureFunction
Defined withPROCEDURE Name(parameters) ... ENDPROCEDUREFUNCTION Name(parameters) RETURNS data type ... ENDFUNCTION
Called withCALL Name(arguments), as a complete statementName(arguments), inside an expression, without CALL
Gives backNothing through a return value; values can come back through BYREF parametersExactly one value, supplied by a RETURN statement
Use it whenA task or group of statements is needed more than once, or is one step of the decompositionA single value is needed inside a calculation, a condition or an output
OUTPUT inside a function is not a return value. If the function prints the answer, the caller cannot use it in an expression, and the marks for RETURNS, RETURN and the call in an expression are all lost at once.

Key terms you must be able to define

Constant
A named storage location whose value is set when it is declared and cannot be changed afterwards, written CONSTANT Identifier = value. Only a literal may be used as the value, and the data type comes from that literal.
Variable
A named storage location whose value can change while the program runs. It is declared with DECLARE Identifier : data type, which reserves the storage and fixes the type but does not give it a value.
Assignment
The statement that stores a value in a variable, written with the left arrow <-. The expression on the right is evaluated first using the current values, and the result is then stored in the single storage location on the left.
DIV
Integer division: the whole-number quotient left after dividing one number by another, so 7 DIV 2 is 3. The fraction is discarded, not rounded.
MOD
Modulus: the remainder left when one number is divided by another, so 7 MOD 2 is 1. Number MOD 2 = 0 is the standard test for an even number.
Built-in function
A function supplied with the language that can be called without being defined, such as LENGTH, MID, RIGHT, INT or RAND. It has a fixed signature: a set number of arguments of fixed types, and a fixed return type.
Library routine
A procedure or function supplied in a library that the program has to make available before it can be called, such as a maths or file-handling library. Like a built-in, it saves the programmer from writing and testing code that already exists.
Procedure
A named block of statements that performs one task, defined from PROCEDURE to ENDPROCEDURE and called with CALL as a complete statement. It returns no value of its own, though it can change the caller's variables through parameters passed by reference.
Function
A named block of statements that returns exactly one value. The header states the type with RETURNS, the body supplies the value with RETURN, and the call is used inside an expression, where the returned value replaces it.
Parameter
An identifier declared in the header of a procedure or function that receives a value when the module is called, and is used inside the body as a variable. A procedure may have none, one or more.
Argument
The actual value supplied in the call, which is copied into, or referenced by, the matching parameter. Arguments must be of the right types and in the same order as the parameters in the header.
Pass by value
Passing a copy of the argument, so the parameter is a separate storage location and any change made to it inside the module is lost when the module ends. This is assumed in 9618 when neither BYVAL nor BYREF is written.
Pass by reference
Passing the address of the caller's variable, marked with BYREF before the parameter, so a change inside the module changes the caller's variable. It is the only way a procedure can give a changed value back, and it should not be used for function parameters.
Return value
The single value a function hands back to the point where it was called, supplied by a RETURN statement and of the type named after RETURNS in the header. Execution of the function ends immediately when RETURN is executed.

Applied to real systems

9618 sets its questions inside systems you already use - a phone, a school network, a supermarket till, a website, a bank. These show how to apply the theory to a context you have not seen before, then you write your own.

Cash machine PIN entry: a post-condition loop with a nested IF

A cash machine has to read a card, ask for a PIN and check it, and it cannot know in advance how many attempts the customer will need. The attempts are handled with a REPEAT loop that contains the INPUT, an attempt counter incremented in the body, and a nested IF that decides whether the PIN matched, and the loop's UNTIL condition tests the counter against the maximum number of attempts the bank allows. If the counter reaches that maximum, the branch outside the loop blocks the card. This is the clearest real case of a post-condition loop: the body must run once, because there is no PIN to test until it has been typed, and the loop stops on an exit condition rather than a known count. It also shows why the counter has to be initialised before the loop and incremented inside it - if the increment is left out, the customer gets unlimited attempts and the loop never ends.

Python's built-in functions and its standard library

Python ships with built-in functions such as len, round and int that can be called immediately, which is exactly what a built-in function means: len("Happy Days") returns 10, and int(27.9) returns 27 because int truncates towards zero. Anything else comes from a library that has to be imported, so random numbers need import random before random.random() or random.randint(1, 6) can be used. The distinction is the one the syllabus draws: a built-in is always available and a library routine has to be made available, and both return values that are used inside expressions rather than printed and forgotten. It is also a reminder that the return types matter, since random.random() gives a REAL between 0 and 1 and would need multiplying and converting before it could be used as a dice roll.

Examination grade boundaries: a CASE with ranges

A grade boundary table maps a whole mark range to a single grade, which is precisely the shape a CASE structure is built for. The mark is the identifier being tested, each boundary becomes a clause such as 80 TO 100 : Grade <- 'A', and an OTHERWISE clause handles a mark that has slipped outside the expected range, which is what turns a marking error into a visible message instead of a silent blank. Written as nested IFs the same logic needs one IF and one ENDIF per boundary and is easy to get wrong at the edges; written as a CASE the ranges sit in one column and their order is obvious. The order still matters, because the clauses are tested in sequence and the first match wins, so overlapping ranges would hand a mark to the wrong grade.

A traffic signal controller: CASE for the lamp sequence and a FOR loop for each phase

At a signal-controlled junction the lamps move through a fixed cycle - red, red and amber, green, amber, then red again - and a controller is naturally written as a CASE on the current state, with each clause setting the lamps for that state and preparing the next one. How long each state is held is a fixed number of timer ticks, which is a count-controlled loop with a known count and a delay inside its body. Nothing in that cycle has to repeat an unknown number of times, which is why the loop is a FOR and not a REPEAT. The example shows the pairing the exam looks for: a fixed set of named states is a CASE, a fixed number of repetitions is a FOR, and the two sit in the same program without either being the wrong choice.

Flashcards

Click a card to flip it. Mark honestly — the tracker uses this.

Q1Write the pseudocode to declare a constant VAT rate of 0.2 and a REAL variable Price, and say what may follow the equals sign in the constant declaration.
CONSTANT VATRate = 0.2, then DECLARE Price : REAL. Only a literal may be used as the value of a constant - never a variable, another constant or an expression - because the value must be fixed at the point of declaration. The data type is not written; it comes from the literal, so 0.2 makes the constant REAL.
Q2What is the difference between <- and = in pseudocode?
<- is assignment and stores the value of the expression on its right in the variable on its left, as in Total <- Total + 1. = is a comparison that returns TRUE or FALSE and belongs in a condition, as in IF Answer = "Y" THEN. Using = as a statement, or <- inside a condition, is a structural error.
Q3What do /, DIV and MOD give for 7 and 2?
/ gives 3.5, because division with / always produces a REAL even when both operands are integers. DIV gives 3, the whole-number quotient. MOD gives 1, the remainder. MOD is used to test whether a number is even (Number MOD 2 = 0) and DIV to drop a fraction.
Q4Write the skeleton of an IF statement with an ELSE clause, and say what ENDIF marks.
IF condition THEN, statements, ELSE, statements, ENDIF. ENDIF marks where the two branches join again, and the statements after it run whichever branch was taken. Every IF needs its own ENDIF, and an ELSE belongs to the nearest IF above it that has not yet been closed.
Q5Write the skeleton of a CASE structure, and state the two rules about its clauses.
CASE OF Identifier, then value : statements for each case, then optionally OTHERWISE : statements, then ENDCASE. Each label is a single value or a range such as 80 TO 100, and a CASE cannot test a compound condition. The clauses are tested in sequence and the first match runs, after which control passes to the statement after ENDCASE; OTHERWISE, if used, must be last.
Q6Write the skeleton of a FOR loop, and state what happens when value1 is greater than value2.
FOR Index <- value1 TO value2, statements, NEXT Index, with an optional STEP increment. The bounds are inclusive, so 1 TO 5 runs five times. If value1 = value2 the body runs once, and if value1 > value2 with a positive step the body does not run at all. The counter is an INTEGER and must not be assigned inside the body.
Q7Write the skeletons of the post-condition and pre-condition loops, and say what each condition means.
REPEAT, statements, UNTIL condition - the condition is tested after the body and is the exit condition: the loop repeats while it is FALSE and stops when it is TRUE, so the body runs at least once. WHILE condition, statements, ENDWHILE - the condition is tested before the body and is the continuation condition: the loop runs while it is TRUE and may run zero times.
Q8Which loop would you choose for a known count, for input that must be validated, and for reading a file that may be empty?
Known count: a FOR loop, because the number of repetitions is settled before the loop starts. Validation: a REPEAT loop, because the body must run at least once before there is any value to test. A file that may be empty: a WHILE loop, because the test for end of file can be made before anything is read, so the body may need to run zero times.
Q9Give three differences between a procedure and a function.
A procedure is defined from PROCEDURE to ENDPROCEDURE and called with CALL as a complete statement; a function is defined from FUNCTION to ENDFUNCTION with RETURNS and its type, and called inside an expression without CALL. A procedure returns no value of its own, while a function returns exactly one value through RETURN. A procedure can change the caller's variables through BYREF parameters; a function returns its single value and its parameters should not be passed by reference.
Q10What is the difference between a parameter and an argument?
A parameter is the identifier declared in the header of the procedure or function and used as a variable inside the body. An argument is the actual value supplied in the call. The arguments must match the parameters in number, order and data type, so PROCEDURE Square(Size : INTEGER) called as CALL Square(SideLength) passes SideLength as the argument for the parameter Size.
Q11What does passing by reference do, how is it marked in 9618, and when is it needed?
Passing by reference gives the module the caller's own variable instead of a copy, so a change inside the module is a change in the caller. It is marked by writing BYREF before the parameter in the header; without BYVAL or BYREF, passing by value is assumed. It is needed whenever a procedure must give a changed value back - a swap, a running total, a count - and a procedure that must return two values needs BYREF on both. It should not be used for function parameters.
Q12Name the parts of a procedure or function interface and say why the interface matters.
The header - PROCEDURE Name(Size : INTEGER) or FUNCTION Max(A : INTEGER, B : INTEGER) RETURNS INTEGER - together with the parameter types and the return type. That is the interface: everything a caller needs in order to call the module correctly, and nothing about how it works inside. Because the body is hidden behind the interface, a module can be rewritten or tested on its own without any other part of the program changing.
0 of 12 marked as known

Exam-style questions

7 questions, 26 marks. Write your answer, then reveal the mark scheme and tick each point you actually made. Answering honestly here is what makes the rest of the site useful.

StateAO11 mark
A count-controlled loop is written as FOR Index <- 2 TO 10 STEP 4, followed by a single OUTPUT statement, then NEXT Index. State how many times the OUTPUT statement is executed.

Mark scheme — tick each point you actually made

Examiner tip: Work through the values rather than dividing the range by the step. The upper bound is included when it is reached exactly, which is what makes the answer three and not two.
WriteAO33 marks
A program must calculate the total price of an item including VAT at 20%. Write pseudocode to declare the VAT rate as a constant, declare variables for the price entered by the user and for the total including VAT, read the price from the keyboard, calculate the total and output it.

Mark scheme — tick each point you actually made

Examiner tip: The constant must be declared with the keyword CONSTANT and a literal value, not DECLARE. Using 0.2 directly in the calculation is not a constant and does not earn the first mark.
CompleteAO33 marks
A program must keep asking the user to enter a mark until a value between 0 and 100 inclusive is entered. The value is read into a variable called Mark, which is already declared as an INTEGER. Complete the following pseudocode by writing the missing statements and the condition. REPEAT ... UNTIL ...

Mark scheme — tick each point you actually made

Examiner tip: One test is not enough: Mark >= 0 on its own accepts 200, and the mark scheme wants both limits joined by AND. Remember that UNTIL states when to stop, not when to carry on.
ExplainAO24 marks
A validation routine must ask the user to enter a mark between 0 and 100 and repeat the request until a valid mark is entered. Explain why a post-condition (REPEAT) loop is more suitable than a pre-condition (WHILE) loop for this routine.

Mark scheme — tick each point you actually made

Examiner tip: The marks are for the at-least-once argument, the position of the INPUT, the exit condition and the avoidance of a duplicated read. A description of what a REPEAT loop does, without comparing it with the WHILE, answers a different question.
WriteAO34 marks
A program records marks as they are entered. It keeps a running total in a variable called Total and a count of the marks in a variable called Count, both of which belong to the main program. Write a procedure called AddMark that is passed one mark and updates both variables in the main program, and write the statement that calls your procedure to add the value held in the variable NewMark.

Mark scheme — tick each point you actually made

Examiner tip: Two values have to come back, so two parameters need BYREF - a function could not do this, because it returns only one value. The order of the arguments in the call must match the order of the parameters in the header exactly.
WriteAO35 marks
A grade is awarded from a mark out of 100 as follows: 80 or more is grade A, 70 to 79 is grade B, 60 to 69 is grade C, and anything below 60 is grade U. Write a function called GradeFor that takes a mark as an INTEGER and returns the grade as a CHAR, using a CASE structure. Then write a statement that outputs the grade for the mark held in the variable StudentMark.

Mark scheme — tick each point you actually made

Examiner tip: The mark scheme rewards the return type in the header, valid case labels, a complete and ordered set of ranges, the RETURN, and a call in an expression. The last point is the one most often missed, because CALL is written out of habit.
ExplainAO26 marks
Explain why a programmer constructing a large program would use procedures and functions, and explain the difference in the way a procedure and a function are used.

Mark scheme — tick each point you actually made

Examiner tip: The first half is about structure, reuse and testing; the second half is about how each is called and what comes back. Answers that only define the two words, with no reference to the construction of the algorithm, are capped in the middle of the mark range.

Exam technique for this topic

  • Learn the closing keywords as a set, because a structure that is opened and not closed scores nothing: ENDIF, ENDCASE, NEXT Identifier, ENDWHILE, ENDPROCEDURE, ENDFUNCTION. CALL is used only for a procedure, never for a function.
  • Write a full program answer in the order declare, initialise, process, output. Marks in these questions are usually awarded for the declaration with the right type, the initialisation before the loop, the correct condition, and the output after the loop - not for the arithmetic in the middle.
  • When a question asks you to justify a loop, answer with two facts: whether the number of repetitions is known before the loop starts, and whether the body must run at least once. Those two sentences are what separates a full-mark justification from a description of the loop.
  • In a procedure or function question, check three things before you move on: the header has the parameter types and, for a function, RETURNS and its type; the value comes back through RETURN and not through OUTPUT; and the call matches the header in the number, order and types of its arguments.
  • Use BYREF only where the caller's variable must change, and say what it changes - 'so the running total in the main program is updated'. A BYREF that is not needed, or a missing one where a total has to come back, loses the same mark twice.

Why students lose marks here

A student wroteA student wrote: REPEAT ... INPUT Answer ... UNTIL Answer <> "Y" for a loop that should keep asking until the user types Y.
Why it loses marksUNTIL states the condition that stops the loop. Answer <> "Y" is TRUE for every answer except Y, so the loop stops the first time the user types anything else and carries on when they type Y - exactly backwards.
The answer that scoresREPEAT, then INPUT Answer, then UNTIL Answer = "Y". The condition after UNTIL is the exit condition: the body repeats while that condition is FALSE and stops as soon as it is TRUE, so the condition must describe the state that ends the loop. The pre-condition equivalent is WHILE Answer <> "Y" ... ENDWHILE, where the condition is the continuation condition - carry on while the answer is not Y. Same job, opposite-looking conditions, and the test sits at opposite ends of the body.
A student wroteA student wrote a function that displays its answer: FUNCTION Average(Total : INTEGER, Count : INTEGER) RETURNS REAL, with OUTPUT Total / Count in the body, called as CALL Average(Sum, N).
Why it loses marksThree separate errors in one module. OUTPUT sends a value to the console instead of returning it, so nothing is handed back to the caller and there is no RETURN statement to supply the value promised by RETURNS REAL. And a function call is not a complete statement, so it cannot be called with CALL.
The answer that scoresFUNCTION Average(Total : INTEGER, Count : INTEGER) RETURNS REAL, with RETURN Total / Count as the last statement, and ENDFUNCTION. The call belongs in an expression, for example OUTPUT "Mean mark: ", Average(Sum, N), where the returned REAL replaces the call and is then printed by the OUTPUT that surrounds it. The header promises a REAL, the RETURN supplies exactly that type, and no CALL is used because a function is not a procedure.
A student wroteA student wrote PROCEDURE AddMark(Mark : INTEGER, Total : INTEGER) with Total <- Total + Mark in the body, then called CALL AddMark(56, Sum) and expected Sum to have increased by 56.
Why it loses marksWithout a keyword, parameters are passed by value, so Total inside the procedure is a copy of Sum. The addition changes the copy, the copy disappears when the procedure ends, and Sum in the caller is exactly as it was. The procedure runs without an error and has no effect at all.
The answer that scoresPROCEDURE AddMark(Mark : INTEGER, BYREF Total : INTEGER), with Total <- Total + Mark in the body and ENDPROCEDURE, called as CALL AddMark(56, Sum). BYREF before the parameter means the parameter refers to the caller's own variable, so the assignment changes Sum itself. The rule is to ask what the module must give back: if nothing, pass by value, which protects the caller's data; if it must change a value in the caller, that parameter needs BYREF, and a procedure that must return two changed values needs BYREF on both.
A student wroteA student wrote a loop over an array of 30 elements as FOR Index <- 1 TO 29 ... NEXT Index, and a loop that should ask exactly five times as FOR Index <- 1 TO 5 STEP 1, with Index <- Index + 1 added at the end of the body.
Why it loses marksThe first loop stops one element early, because the upper bound is inclusive - 1 TO 29 visits 29 values, not 30. The second adds to the counter by hand inside a count-controlled loop, so each repetition moves the counter twice and the body runs three times instead of five.
The answer that scoresFOR Index <- 1 TO 30 ... NEXT Index for an array declared ARRAY[1:30], because both bounds are included and the count is upper bound minus lower bound plus one. For five repetitions, FOR Index <- 1 TO 5 ... NEXT Index with nothing inside the body that touches Index, because NEXT is what advances the counter. The bounds should come from the declaration, and the counter should be left to the loop: a FOR loop whose counter is assigned inside the body no longer has a known number of repetitions, which was the only reason for choosing it.
A student wroteA student replaced a nested IF with CASE OF Total and wrote clauses such as Total > 100 AND Member = TRUE : Discount <- 20, and left out OTHERWISE because all the values were 'covered'.
Why it loses marksA CASE tests a single identifier against fixed values or ranges. It cannot evaluate a compound condition on two variables, so Total > 100 AND Member = TRUE is not a valid case label - that logic belongs in an IF. Leaving out OTHERWISE also leaves every value that matched no clause with no branch to run at all.
The answer that scoresIf the branches depend on two variables or on compound conditions, use nested IF statements, one condition per IF, each closed with its own ENDIF. If the choice really is one identifier against a list, use CASE OF Identifier with labels that are single values or ranges such as 80 TO 100, and finish with OTHERWISE : followed by the default action, so an unexpected value is handled deliberately rather than falling through. Ranges in a CASE must not overlap either, because the clauses are tested in sequence and the first match wins.