SPM KMK 2216 common mistakes
SPM KMK 2216 · Understand the traps and how to avoid them.
Writing pseudocode that mixes Malay and English keywords inconsistently within one algorithm, e.g. starting with 'SET' but later using 'PAPAR' and 'INPUT' in the same block, or inventing keywords like 'BACA' where the syllabus expects a defined set.
Candidates revise from several sources and absorb different keyword conventions, then reproduce them verbatim under exam pressure without checking which notation the question paper uses. Markers accept a consistent, defined pseudocode style but penalise ambiguity about whether a line is input, assignment or output.
What to do instead
Before the exam, fix one keyword set (e.g. INPUT, OUTPUT, SET, IF...THEN...ELSE...ENDIF, WHILE...ENDWHILE, FOR...ENDFOR) and drill writing full algorithms using only that set. In the answer, add a one-line note defining any non-obvious keyword, and read back each line asking 'is this clearly input, processing or output?'
Confusing a variable declaration with an assignment, and writing a declaration that also initialises implicitly, e.g. treating 'DECLARE Count : INTEGER' as setting Count to 0 and then using it in a running total without an explicit assignment.
In many languages a declared variable happens to start at zero or is undefined, and candidates generalise from one language they have practised. Pseudocode questions often test whether the candidate knows that declaration reserves storage while assignment gives a value.
What to do instead
Always write an explicit initialisation line immediately after any declaration used in accumulation or counting (SET Total <- 0, SET Count <- 0). When tracing, mark declared-but-unassigned variables as 'undefined' and state that using them is an error rather than assuming zero.
Applying integer division and MOD incorrectly, for example computing the digit sum of 4721 as 4+7+2+1 by dividing by 10 each time but forgetting to subtract the remainder, or predicting 7/2 = 3.5 in a context where both operands are integers.
Candidates learn DIV and MOD as definitions but do not rehearse them inside loops where the quotient and remainder must be used together. Real languages differ on whether / on integers truncates, so they fall back on the calculator habit.
What to do instead
Practise the standard digit-extraction pattern until automatic: Digit <- N MOD 10; N <- N DIV 10. Trace it on paper for 4721 and for 1000. In any expression, first label each operand's type, then apply the rule that integer / integer yields the integer quotient only when the question's pseudocode defines it so; otherwise state the assumption.
Producing an IF structure with dangling or unmatched branches, e.g. an ELSE that attaches to the wrong IF in a nested selection, or omitting ENDIF so the following statement is swallowed into the branch.
Indentation is lost when handwriting under time pressure, and candidates translate directly from English sentences ('if not a and b then...') without resolving operator precedence or block boundaries.
What to do instead
Always draw vertical guide lines from each IF to its ENDIF before writing the body, and indent every nested level by a fixed two spaces. For compound conditions, bracket explicitly: IF (NOT A) AND B THEN. After writing, re-read from the innermost IF outward to confirm each ELSE belongs to the intended IF.
Choosing a WHILE loop for a count-controlled problem and then forgetting to update the counter inside the body, producing an infinite loop, or using a FOR loop when the number of iterations is not known in advance.
Candidates pattern-match on 'loop' rather than on whether the iteration count is known before entry. The counter increment is a single easily-omitted line that does not affect the first iteration, so casual desk-checking misses it.
What to do instead
Decide by one question: is the number of repetitions known before the loop starts? If yes use FOR; if no use WHILE and write the update line as part of the loop skeleton before filling in the body. Trace at least three iterations including the exit test, and state the loop invariant (e.g. 'Total holds the sum of the first i values').
Off-by-one errors in array traversal, such as looping FOR i <- 1 TO n on a zero-indexed array, or writing a search that stops at n-1 and never inspects the last element.
Textbook pseudocode often uses 1-based indexing while the language the candidate practises uses 0-based indexing, and the two conventions get blended. The error is invisible on arrays of length 1 or 2, so test data rarely exposes it.
What to do instead
At the top of every array answer, write the index bounds explicitly (e.g. 'assume indices 0..n-1'). Then write the loop as FOR i <- 0 TO n-1. Test the algorithm mentally on an array of length 1 and on a target stored in the final position; both must succeed.
Treating a two-dimensional array as a list of rows without deciding which subscript is the row and which is the column, so that a nested loop sums columns when the question asks for row totals, or transposes the access pattern.
Both subscripts are integers and the code compiles or reads plausibly either way; the mistake only surfaces in the output. Candidates also copy a memorised nested-loop template without re-deriving which loop should be outer.
What to do instead
Write the declaration with named dimensions (Grid[row][col]) and annotate the loops: outer loop over rows, inner loop over columns for row-wise processing. State in one sentence what the inner loop accumulates and reset that accumulator at the start of each outer iteration.
Confusing a function that returns a value with a procedure that does not, e.g. writing a procedure to compute an average but never assigning the result, or calling a function as a standalone statement and discarding its return value.
The distinction is syntactic in some languages and semantic in others, and candidates remember 'function = reusable block' rather than the return contract. Parameter passing by value versus by reference compounds the confusion.
What to do instead
For each module, first write its contract: name, inputs with types and passing mode, and output (a returned value or a modified reference parameter). If it must produce a value used in an expression, make it a function with an explicit RETURN. If it must change a caller's variable, mark that parameter as by-reference and show the caller's variable changing in a trace.
Opening a file for reading without checking that it exists or that the open succeeded, and closing it only on the success path, so an error leaves the handle open or the program crashes with an unhandled exception.
Candidates write the happy path first because that is what their notes show, and error handling is treated as an optional extra rather than part of the algorithm. The exam question often awards marks specifically for the failure branch.
What to do instead
Use a fixed skeleton: attempt to open; IF open failed THEN report and stop; otherwise process inside a protected block; ensure close runs on every path (finally or after the loop). Write the error branch before the processing loop so it cannot be forgotten.
Validating input only once before a loop instead of inside it, so a rejected first value is re-prompted correctly but a rejected later value is accepted, or accepting sentinel values as ordinary data.
The validation pattern is learned as a single 'read, check, re-read' block and then pasted outside the loop. Sentinel-terminated loops add a second condition that candidates test against the wrong value.
What to do instead
Place the validation loop immediately around every read, including reads inside larger loops, and test the sentinel before validating the value as data. Trace with an input sequence containing an invalid value in the middle and a sentinel at the end, confirming the loop rejects the first and stops at the second.