Data Structures

AS Level

Record Type Data

Master user-defined record (struct) data types in CIE AS Level pseudocode. Learn to define a record with TYPE ... ENDTYPE, declare record variables, assign fields with dot notation, build arrays of records, mark unused fields with sentinel values, and iterate, count and print records with loops and worked tasks (Book, Employee and Patient records).

1.1 What Is a Record?

A record is a user-defined data structure that stores related pieces of data of different data types together under one identifier. Think of a record as a box with several labeled compartments, where each compartment holds a specific type of information about the same entity.

For example, if you are storing information about a student, you might need:

  • Name — a piece of text (STRING)
  • Age — a whole number (INTEGER)
  • Email — a piece of text (STRING)

Instead of storing these as three separate variables, you combine them into a record called Student. The record becomes a single named container holding all the related data for one student.

Why use records?

  • Organisation: Related data is stored together under one identifier.
  • Ease of access: You can access all the data for one entity (such as a student) at once.
  • Clarity: Each field has a meaningful name (e.g. Name, Email) — anyone reading the code instantly knows what each piece of data means.
  • Reusability: Define the type once and use it anywhere — for a single variable, an array, a parameter, or a subroutine return value.

Separate variables vs a record — side-by-side comparison

AspectSeparate variablesRecord
IdentifierThree variables: StudentName, StudentAge, StudentEmailOne record variable: MyStudent (holds all three fields)
Data typesEach variable has its own type, but no link between themEach FIELD has its own type, all grouped under one identifier
Passing to a subroutineMust pass three separate argumentsPass one record argument — all fields travel together
Storing many entitiesNeed three parallel arrays (names[], ages[], emails[])One array of records (Students[1:N]) — each slot is a full record
ClarityEasy to mix up which age goes with which nameEach entity's data stays together — no chance of mix-up

Key idea: Each field inside a record can have a different data type — that is the main difference from an array, where every element must share the same type. A record is the natural choice whenever one entity (a student, a book, an employee) has several attributes of different kinds.

1.2 Declaring a Record Type (TYPE ... ENDTYPE)

To create a record, you define a new record type using the TYPE ... ENDTYPE block. Inside the block, each field is declared with a DECLARE statement and given its own data type.

Example: declare the Student record type

TYPE Student
  DECLARE StudentID : STRING
  DECLARE Name : STRING
  DECLARE Age : INTEGER
  DECLARE Email : STRING
ENDTYPE

What each keyword does

  • TYPE — starts the definition of the record.
  • Student — the name of the record type. You choose this name; it is used later when declaring variables.
  • DECLARE — lists each field inside the record (here StudentID, Name, Age, Email). Each field has its own data type.
  • ENDTYPE — ends the record definition.

A second example: the Employee record type

TYPE Employee
  DECLARE EmployeeID : INTEGER
  DECLARE Name : STRING
  DECLARE Position : STRING
  DECLARE Salary : REAL
ENDTYPE

The same pattern: TYPE starts the block, the type name (Employee) follows, four DECLARE lines define the fields (each with its own data type — INTEGER, STRING, STRING, REAL), and ENDTYPE closes the block. Salary is REAL because salaries include decimals.

Important: TYPE ... ENDTYPE only defines a new data type — it is a template. It does not create a variable. To actually store data you must separately declare a variable of that type (covered in section 1.3). Writing the TYPE block alone gives you no usable storage.

1.3 Record Variables & Dot Notation

Once the record type exists, you can declare a record variable — a named piece of storage whose type is your record. Then you assign values to each field using dot notation (variable.field).

Example: declare a Student record variable and fill its fields

DECLARE MyStudent : Student
MyStudent.StudentID <- "S12345"
MyStudent.Name <- "Alice"
MyStudent.Age <- 18
MyStudent.Email <- "alice@example.com"
  • DECLARE MyStudent : Student creates a record variable of type Student.
  • Each field is assigned individually using dot notation: MyStudent.StudentID <- "S12345"writes the string "S12345" into the StudentID field.
  • MyStudent is the name of the record variable; StudentID, Name, Age and Email are the fields defined inside the type.

Reading a field with dot notation

Dot notation works both ways — you can also read the value of a field:

OUTPUT MyStudent.Name  // outputs: Alice

Writing to a field

MyStudent.Age <- 18

The arrow <- stores the value on the right into the field on the left.

Reading a field

OUTPUT MyStudent.Age

MyStudent.Age on the right of the arrow (or inside OUTPUT) reads the value stored in the field.

Worked task: declare and fill a Book record

Using a Book record type with fields BookID : INTEGER, Title : STRING, Author : STRING, Price : REAL, declare a record variable MyBook and assign it the values BookID = 101, Title = "Pseudocode Simplified", Author = "Moshikur Rahman", Price = 5.99.

TYPE Book
  DECLARE BookID : INTEGER
  DECLARE Title : STRING
  DECLARE Author : STRING
  DECLARE Price : REAL
ENDTYPE

DECLARE MyBook : Book
MyBook.BookID <- 101
MyBook.Title <- "Pseudocode Simplified"
MyBook.Author <- "Moshikur Rahman"
MyBook.Price <- 5.99

To extend this and store a second book, simply declare DECLARE MyBook2 : Book and assign its fields the same way — the type definition is reusable.

Key idea: The pattern variable.field <- value is the only way to write to one field of a record. You cannot write a whole record in one go (e.g. MyStudent <- "Alice") because the record has multiple fields of different types — the program would not know which field to fill.

1.4 Arrays of Records

A single record variable holds data for one entity. To store information for many entities — many students, many books, many employees — use an array of records. Think of it as a list of boxes, where each box contains the complete data for one entity.

Declaring an array of records

DECLARE Students : ARRAY[1:100] OF Student
  • Students — the name of the array.
  • ARRAY[1:100] — indicates there are 100 slots in the array, indexed from 1 to 100.
  • OF Student — each element in the array is of type Student. That means Students[i] is a complete Student record (with StudentID, Name, Age and Email).

Accessing and updating fields in an array of records

Combine the array index (square brackets) with dot notation (dot + field name):

Students[1].Name <- "Alice"
Students[1].Age <- 20

// Reading works the same way:
OUTPUT Students[1].Name   // outputs: Alice
  • Students[1] — refers to the first Student record in the array.
  • .Name or .Age — refers to specific fields inside that record.
  • The order is always: array → index → dot → field.

Worked example: array of Employee records

TYPE Employee
  DECLARE EmployeeID : INTEGER
  DECLARE Name : STRING
  DECLARE Position : STRING
  DECLARE Salary : REAL
ENDTYPE

DECLARE Employees : ARRAY[1:50] OF Employee

// Update the Name and Salary of the 2nd employee
Employees[2].Name <- "John"
Employees[2].Salary <- 45000.50

The TYPE block defines the Employee record type once. Then DECLARE Employees : ARRAY[1:50] OF Employee creates an array of 50 such records. Finally, Employees[2].Name <- "John" updates just the Name field of the second record, and Employees[2].Salary <- 45000.50 updates just the Salary field.

Without records — parallel arrays

DECLARE StudentID : ARRAY[1:100] OF STRING
DECLARE Name : ARRAY[1:100] OF STRING
DECLARE Age : ARRAY[1:100] OF INTEGER
DECLARE Email : ARRAY[1:100] OF STRING

Name[1] <- "Alice"
Age[1] <- 18

Four arrays must be kept in sync — easy to mix up which age goes with which name. Passing one student to a subroutine means passing four arguments.

With records — one array of records

DECLARE Students : ARRAY[1:100] OF Student

Students[1].Name <- "Alice"
Students[1].Age <- 18

One array holds 100 complete records. Each Students[i] is one student's full data. Passing a student to a subroutine = one argument.

Pattern: An array of records is the standard pattern for managing collections of entities — a class register, a library catalogue, a staff database. Each element of the array is a whole record; fields are accessed by name with dot notation, NOT by a second index.

1.5 Sentinel Values & Counting Records

Sometimes a field is not yet known — a book with no price recorded, a patient with no diagnosis yet. Rather than leave the field blank (which is not allowed for typed fields), you store a sentinel value: a special, agreed-upon value that signals “no real data here”.

Sentinel value conventions

  • For a numeric field (INTEGER or REAL) where real values are positive, use -1 as the sentinel.
  • For a STRING field, use a descriptive sentinel like "Undiagnosed" or "Unknown".
  • For an INTEGER field with a limited valid range (e.g. Age 0..120), use a value outside that range like -1 or 999.

Example: a book with no price recorded

Library[2].Price <- -1  // second book has no price yet

Here -1 is the sentinel value for an unused Price field. Because prices are normally positive, -1 can never be a genuine price — whenever the program sees -1 it knows the price is missing.

Example: an undiagnosed patient

Patients[2].Diagnosis <- "Undiagnosed"  // no diagnosis yet

For the string field Diagnosis, the sentinel is the string "Undiagnosed". Any code that reads a patient record can check IF Patients[i].Diagnosis = "Undiagnosed" THEN ... to handle the missing-data case.

Important: Choose sentinel values that could never appear as a real value. Using 0 for a missing Price is a bad choice — 0 could mean “free”. Using "" (empty string) for a missing Diagnosis is ambiguous and harder to read in output. Always pick a value that is unmistakably a placeholder.

Iterating and counting records

A common task is to loop through an array of records and count those that match a condition. Because each element of the array is a complete record, you can test any field in the loop body using dot notation.

Worked example: count books with Price > 20

Assume the Library array holds 500 Book records. The loop scans every record; whenever Library[i].Price is greater than 20, Count is incremented by 1.

DECLARE Count : INTEGER
DECLARE i : INTEGER

Count <- 0
FOR i <- 1 TO 500
  IF Library[i].Price > 20 THEN
    Count <- Count + 1
  ENDIF
NEXT i

OUTPUT "Number of books with price > 20: ", Count

Note how the sentinel value -1 behaves correctly here: since -1 is NOT greater than 20, books with the missing-price sentinel are automatically excluded from the count. This is exactly why we use a sentinel that the condition naturally filters out.

Parallel practice task: count patients older than 60

Using the Patient array (with fields PatientID, Name, Age, Diagnosis), write pseudocode to count how many patients are older than 60. The pattern is identical to the book example above — only the field name and the bound change.

DECLARE Count : INTEGER
DECLARE i : INTEGER

Count <- 0
FOR i <- 1 TO 1000
  IF Patients[i].Age > 60 THEN
    Count <- Count + 1
  ENDIF
NEXT i

OUTPUT "Number of patients older than 60: ", Count

1.6 Printing Records & Worked Tasks Summary

To print every record in an array of records, you only need a single FOR loop — one loop per array, not one loop per field. Inside the loop body, output whichever fields you want using dot notation.

Worked example: print Title and Author of all books

FOR i <- 1 TO 500
  OUTPUT "Title: ", Library[i].Title
  OUTPUT "Author: ", Library[i].Author
NEXT i

For each i from 1 to 500, two OUTPUT statements print the Title and the Author of Library[i]. Each OUTPUT call prints on its own line, so each book produces two lines of output. Note: only ONE loop is needed — fields are accessed by name, not by a second index.

Parallel practice task: print Patient Name and Diagnosis

FOR i <- 1 TO 1000
  OUTPUT "Name: ", Patients[i].Name
  OUTPUT "Diagnosis: ", Patients[i].Diagnosis
NEXT i

Worked task 1: declare the Book record

A library tracks book information with: BookID (Integer), Title (String), Author (String), Price (Real). Write pseudocode to declare the record structure Book.

TYPE Book
  DECLARE BookID : INTEGER
  DECLARE Title : STRING
  DECLARE Author : STRING
  DECLARE Price : REAL
ENDTYPE

Worked task 2: declare the Library array of 500 books

Using the Book record from Task 1, declare an array that can store details for up to 500 books.

DECLARE Library : ARRAY[1:500] OF Book

Each Library[i] is now a complete Book record — you can fill and read its BookID, Title, Author and Price fields with dot notation.

Worked task 3: assign values to Library[1]

Assign the Title “1984”, the Author “George Orwell”, and the Price 12.99 to the first book in the Library array.

Library[1].Title <- "1984"
Library[1].Author <- "George Orwell"
Library[1].Price <- 12.99

Worked task 4: indicate an unused Price with -1

Some books in the library are missing prices. Indicate an unused Price field by assigning the sentinel value -1 to the second book.

Library[2].Price <- -1

The parallel Patient practice task uses Patients[2].Diagnosis <- "Undiagnosed" for the string Diagnosis field — a string sentinel for a string field.

Worked task 5: count books with Price > 20

Write pseudocode to count how many books in the Library array have a Price greater than 20. Assume there are 500 books in the array.

DECLARE Count : INTEGER
DECLARE i : INTEGER

Count <- 0
FOR i <- 1 TO 500
  IF Library[i].Price > 20 THEN
    Count <- Count + 1
  ENDIF
NEXT i

OUTPUT "Number of books with price > 20: ", Count

Worked task 6: print Title and Author of all books

Write pseudocode to output the Title and Author of every book in the Library array.

FOR i <- 1 TO 500
  OUTPUT "Title: ", Library[i].Title
  OUTPUT "Author: ", Library[i].Author
NEXT i

Key Points Summary

A record is a user-defined data structure that stores related data of DIFFERENT types under ONE identifier.

Define a record type with TYPE ... ENDTYPE; each field is DECLARE FieldName : DataType.

TYPE only defines a template — you must DECLARE a variable of that type to use it.

Access fields with dot notation: variable.field (read) and variable.field <- value (write).

An array of records DECLARE name : ARRAY[1:N] OF RecordType stores N complete records.

Access a field of a record in an array with array[i].field.

Use sentinel values for unused fields: -1 for numeric, "Undiagnosed" or "Unknown" for string.

A sentinel must be a value that could NEVER appear as real data.

Loop through an array of records with a single FOR loop — fields are accessed by name.

Counting/printing uses IF Library[i].Field condition THEN inside a FOR i <- 1 TO N loop.

Exam tip: Whenever an exam question describes an entity with several attributes of different types (a student with ID + name + age + email, a book with ID + title + author + price), reach for a TYPE ... ENDTYPE record. When it then asks you to manage “many” of those entities, declare an ARRAY[1:N] OF RecordType and use a single FOR loop with dot notation to access, count or print the fields.

Question Bank

Answer all questions, then press Submit Quiz to see your score.

0/12 answered

Question 1Multiple Choice

Which of these best defines a record in CIE pseudocode?

Question 2True / False

A single record can hold fields of more than one data type — for example, a STRING Name, an INTEGER Age and a REAL Salary.

Question 3Multiple Choice

Which block of pseudocode correctly declares a record type called Student with four fields?

Question 4Multiple Choice

After declaring TYPE Student ... ENDTYPE, which statement declares a record variable called MyStudent?

Question 5Multiple Choice

Which statement assigns the value 18 to the Age field of the record variable MyStudent?

Question 6True / False

The TYPE ... ENDTYPE block defines a new data type — it does NOT by itself create a usable variable.

Question 7Multiple Choice

Which declaration creates an array that can store up to 500 Book records, indexed from 1 to 500?

Question 8Multiple Choice

Given TYPE Book and DECLARE Library : ARRAY[1:500] OF Book, which statement assigns "1984" to the Title of the first book?

Question 9Multiple Choice

DECLARE Library : ARRAY[1:500] OF Book
DECLARE Count : INTEGER
DECLARE i : INTEGER
Library[1].Price <- 25.00
Library[2].Price <- -1
Library[3].Price <- 30.00
Count <- 0
FOR i <- 1 TO 3
  IF Library[i].Price > 20 THEN
    Count <- Count + 1
  ENDIF
NEXT i
OUTPUT "Counted: ", Count

Question 10True / False

A good sentinel value should be a value that could never appear as a genuine piece of data in that field.

Question 11Multiple Choice

DECLARE Count : INTEGER
DECLARE i : INTEGER
Count <- 0
FOR i <- 1 TO 500
  IF Library[i].Price > 20 THEN
    Count <- Count + 1
  ENDIF
NEXT i
OUTPUT "Number of books with price > 20: ", Count

Question 12Multiple Choice

Which loop correctly outputs the Title and Author of every book in an array Library of 500 Book records?

Answer all 12 questions to enable submission.