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
| Aspect | Separate variables | Record |
|---|---|---|
| Identifier | Three variables: StudentName, StudentAge, StudentEmail | One record variable: MyStudent (holds all three fields) |
| Data types | Each variable has its own type, but no link between them | Each FIELD has its own type, all grouped under one identifier |
| Passing to a subroutine | Must pass three separate arguments | Pass one record argument — all fields travel together |
| Storing many entities | Need three parallel arrays (names[], ages[], emails[]) | One array of records (Students[1:N]) — each slot is a full record |
| Clarity | Easy to mix up which age goes with which name | Each 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.
What Is a Record?
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
ENDTYPEWhat 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 (hereStudentID,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
ENDTYPEThe 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.
Declaring a Record Type (TYPE ... ENDTYPE)
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 : Studentcreates a record variable of typeStudent.- Each field is assigned individually using dot notation:
MyStudent.StudentID <- "S12345"writes the string"S12345"into theStudentIDfield. MyStudentis the name of the record variable;StudentID,Name,AgeandEmailare 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: AliceWriting to a field
MyStudent.Age <- 18The arrow <- stores the value on the right into the field on the left.
Reading a field
OUTPUT MyStudent.AgeMyStudent.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.99To 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.
Record Variables & Dot Notation
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 StudentStudents— 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 typeStudent. That meansStudents[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: AliceStudents[1]— refers to the first Student record in the array..Nameor.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.50The 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] <- 18Four 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 <- 18One 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.
Arrays of Records
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
-1as 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
-1or999.
Example: a book with no price recorded
Library[2].Price <- -1 // second book has no price yetHere -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 yetFor 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: ", CountNote 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: ", CountSentinel Values & Counting Records
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 iFor 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 iWorked 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
ENDTYPEWorked 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 BookEach 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.99Worked 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 <- -1The 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: ", CountWorked 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 iKey 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.