Lecture Notes - Programming
Lecture Notes - Programming
Year 1
PROGRAMMING
Lecture Notes
Developed by
Michael R Chinguwo
TRADEMARK ACKNOWLEDGEMENTS
Microsoft Word, Microsoft Excel, Windows and Visual Basic are registered trademarks of
Microsoft Corporation. Adobe Reader is a registered trademark of Adobe Inc. Other brand
names and product names are trademarks or registered trademarks of their respective
holders.
COPYRIGHT
Copyright© 2026 by Michael R Chinguwo. All rights reserved.
ii
LIST OF TABLES
iii
LIST OF FIGURES
iv
TABLE OF CONTENTS
v
UNIT 4: PROGRAM DESIGN ....................................................................................... 68
Introduction ................................................................................................................ 68
Unit outcomes ............................................................................................................ 68
Key terms ................................................................................................................... 68
4.1 Program Statements ............................................................................................ 69
4.2 Algorithm Design .................................................................................................. 73
4.3 Algorithm notations .............................................................................................. 80
4.4 IPO Model ............................................................................................................ 84
Unit summary ............................................................................................................. 88
vi
7.2. Array ................................................................................................................. 169
7.3. Two-Dimensional Arrays ................................................................................... 174
7.4. Manipulating Array Contents ............................................................................. 177
Unit summary ........................................................................................................... 183
vii
Unit summary ........................................................................................................... 248
viii
UNIT 14: FILE HANDLING ......................................................................................... 389
Introduction .............................................................................................................. 389
Unit outcomes .......................................................................................................... 389
Key terms ................................................................................................................. 389
14.1. File .................................................................................................................. 390
14.2. File Streams .................................................................................................... 393
14.3. Reading from a File and Writing to a File ........................................................ 397
14.4. Binary Files ..................................................................................................... 403
14.5. Random File Access ....................................................................................... 407
Unit summary ........................................................................................................... 411
ix
MODULE OVERVIEW
In the first year of the Bachelor of Science in Management Information Systems, Bachelor
of Science in Information Technology, Bachelor of Science in Software Engineering, and
Bachelor of Science in Cybersecurity programs, the curriculum introduces Programming
as a core subject. This subject equips students with the skills needed to instruct
computers to perform practical tasks and solve complex problems.
x
Unit 3: Operators and Expressions
This unit introduces you to program statements, operators, expressions such as
arithmetic expressions, relational expressions, logical expressions, and conditional
expression. This unit also discusses precedence and associativity rules when two
operators compare for the same operand.
Unit 6: Functions
In this unit you will learn how and why to modularize programs, using both functions and
procedures. Parameter passing is covered, with emphasis on when arguments should be
passed by value versus when they need to be passed by reference. Scope of variables
is covered and sections are provided on local versus global variables. Overloaded
functions, Inline functions and Recursive functions are also introduced and demonstrated.
you will also learn how you can create header files and include them in the program.
Finally, you will differentiate the stack and heap memory segments.
xi
Unit 7: Arrays
In this unit student learns how to create and work with single and multidimensional arrays
such as declaring, initializing, assigning values and displaying values. Students also learn
to create tables using two-dimensional arrays, and to analyze the array data by row or by
column. The unit also covers how to pass arrays to functions and advantages and
disadvantages of arrays.
Unit 9: Pointers
This unit explains how to use pointers; this includes reference and dereference operators,
declaration and initialization of pointers, assigning values to pointers, pointer arithmetic,
arrays and pointers. Students will also learn pointer to pointer, pointers and arrays,
pointers and functions as well as dynamic memory allocation.
xii
Unit 12: Object-Oriented Programming Concepts
In this unit, we'll get to know Object-Oriented Programming (OOP) basics. Find out why
OOP is useful and what good stuff it brings. Learn about objects, classes, and methods—
like building blocks for making your code organized. We'll also explore encapsulation,
which helps keep things neat, and check out inheritance, a way to create family-like
structures. Lastly, discover polymorphism, where one thing can do different jobs, making
your programming more flexible.
xiii
Visual Icons
In this module, you will come across different icons (symbols) and the following are their
meanings:
Icon What the icon entails
Introduction: This is an advanced organizer that tells what you
will learn from a unit of study.
Outcomes: These define the type of knowledge, skills, and
attitudes you should be able to display after going through the
lessons in the unit.
Key terms: These are words or phrases which will help you
understand lessons in the unit.
Lessons: This is content you must read and understand to
achieve the stated unit objectives.
Activity: This tells you the tasks you should perform to facilitate
your learning from the unit.
Summary: Reminds you of what you have learned in a unit.
xiv
UNIT
1 UNIT 1: INTRODUCTION TO PROGRAMMING
Introduction
In the big world of technology, computers are super versatile because they can do a lot
of different things. They're like really well-made tools that can carefully follow instructions.
When you tell them what to do through programs or software, they happily carry out tasks,
opening up a bunch of possibilities. This unit is like your key to learning how to tell
computers what to do. You will learn the basics of computer program, check out tools for
making programs, and go through the important steps to create a computer program.
Unit outcomes
By the end of this Unit, you must be able to:
• define ‘computer programming’
• explain different programming language generations
• explain program compilation process
• discuss programming stages
Key terms
Ensure that you understand the following key terms or phrases used in this unit: computer
program, computer programming, programmer, source code, program execution,
programming language, translator, syntax, semantic, machine code, compiler, interpreter,
debugger and profiler.
1
Software makes a computer a truly universal machine transforming it into the proper tool
for the task at hand. Examples of computer programs which you can install in the modern
computers include Microsoft Word, Microsoft Excel, Adobe Reader, VLC Media Player,
etc.
Activity 1.1a
What has to be done before a program can be executed in a computer? How is the
program executed by the CPU?
2
communicate with computers using machine language. Its language is hard to learn. It
is just combinations of 1s and 0s. So, there are other languages which are used to
communicate with computers. But they are to be translated into machine language to be
understood by the computers.
Hundreds of languages are in use today. These may be divided into three general types:
i. Machine languages
ii. Assembly languages
iii. High-level languages
1. Machine languages
Any computer can directly understand only its own machine language, defined by its
hardware design. Machine languages generally consist of strings of numbers (ultimately
reduced to 1s and 0s) that instruct computers to perform their most elementary operations
one at a time. Machine languages are machine dependent.
2. Assembly languages
Programming in machine language was simply too slow and tedious for most
programmers. Instead of using the strings of numbers that computers could directly
understand, programmers began using English-like abbreviations to represent
elementary operations. These abbreviations formed the basis of assembly languages.
Translator programs called assemblers were developed to convert early assembly-
language programs to machine language at computer speeds.
3. High-level languages
Computer usage increased rapidly with the advent of assembly languages, but
programmers still had to use many instructions to accomplish even the simplest tasks. To
speed the programming process, high-level languages were developed in which single
statements could be written to accomplish substantial tasks. Translator programs called
compilers convert high-level language programs into machine language. High-level
3
languages allow you to write instructions that look almost like every day English and
contain commonly used mathematical notations.
From the programmer’s point of view, high-level languages are preferable to machine and
assembly languages.
Activity 1.2a
What are the major advantages of using a high-level language rather than internal
machine code or assembler language?
iii. Operators
Operators perform operations on one or more operands. An operand is usually a
piece of data, like a number.
iv. Punctuation
Punctuation characters that mark the beginning or ending of a statement, or
separate items in a list.
4
v. Syntax
Rules that must be followed when constructing a program. Syntax dictates how
key words and operators may be used, and where punctuation symbols must
appear.
Syntax
Syntax are rules of writing statements in the program. It is actually a grammar of
programming language. The syntax of a language refers to the way pieces of the
language are arranged to make well-formed sentences.
Semantics
Semantic is the meaning of each statement in the program. Syntactically valid statement
does not imply Semantically valid. To illustrate this, let us consider the following
sentence;
She eats a lot of water.
This statement is grammatically correct (syntactically valid) in English but it is not sensible
(not semantically valid).
5
1.2.4 Programming Languages Examples
The following are well-known high-level programming languages:
6
1.2.5 Programming Language Generations
Programming language generations are classifications of programming languages, which
reference different eras of programming history. This classification indicates how
programming power is increasing. The Programming Language Generations are:
i. First Generation Programming Language (1GL)
• Machine language
• Statements are written in binary code (1s and 0s)
• Each statement corresponds to one machine action
• Machine dependent
7
• Often used to access data in a database
• Example is SQL (Structured Query Language)
Activity 1.2b
Discuss the differences between a high-level language and a low-level
language?
8
• Editors
• Translators
• Debuggers
• Profilers
Editors
An editor is used to type your program. An editor allows the user to enter the program
source code and save it to files. Most programming editors increase programmer
productivity by using colors to highlight language features. Some syntax-aware editors
can use colors or other special annotations to alert programmers of syntax errors before
the program is compiled. Name and version of text editor can vary on different operating
systems. For example, Notepad is an Editor found in Windows Operating System.
The files you create with your editor are called source files and for C++ they are typically
named with the extension. cpp,. cp, or .c. Examples of editors include: Windows Notepad,
OS Edit command, Brief, Epsilon, EMACS, vim or vi. A text editor should be in place to
start your programming.
Translator
Translator is a computer program that converts given program written in one
programming language into functionally equivalent program in another language.
Programs are usually not written in a machine language, For the computer to understand
our program, a translator is required to translate our program into a machine language.
The collection of statements written in human-readable programming languages (not in
machine language) is called source code.
Source code is translated into machine-readable instructions called machine code or
object code. There are three types of translators:
• Assemblers
• Compilers
• Interpreters
9
Assemblers
The program that translates program in low level language (assembly language) into
machine code. Statements are translated at 1:1 ratio. One symbol in assembly language
maps to exactly one machine code.
Compiler
The program that translates program in high level language into machine language. With
compilers the whole program is scanned and translated first before execution. If any error,
the program translation fails hence it does not execute until the error is corrected. A
compiler translates the source code to target code. The target code may be the machine
language for a particular platform or embedded device. The target code could be another
source language. Compiled program executes faster than interpreted. Compiled program
requires more memory to run than interpreted program.
Interpreter
The program that translates program in high level language into machine language. This
translates and executes program line by line. The first line is translated and executed
before second line is translated. The second line is translated and executed before third
line is translated. And so on… If there is any error, the program executes until the
statement (line) with the error is reached. Interpreted program executes slower than
compiled. Interpreted program executes slower than compiled.
10
1.3.2 The Compilation Process
Figure 1.1: Source code to target code sequence (Adapted from Halterman, 2018,
p. 4)
11
a linker. Once the linker has finished, an executable file is created. The executable file
contains machine language instructions, or executable code, and is ready to run on the
computer. Figure 1.2 illustrates the process of translating a C++ source file into an
executable file.
Figure 1.2: Process of translating a C++ source file into an executable file
(Adapted from Gaddis, Walters, & Muganda, 2020, p. 11)
Debuggers
A debugger allows a programmer to more easily trace a program’s execution in order to
locate and correct errors in the program’s implementation. A developer can
simultaneously run a program and see which line in the source code is responsible for
the program’s current actions. The programmer can watch the values of variables and
other program elements to see if their values change as expected. Debuggers are
valuable for locating errors (also called bugs) and repairing programs that contain errors.
12
Profilers
A profiler collects statistics about a program’s execution allowing developers to tune
appropriate parts of the program to improve its overall performance. A profiler indicates
how many times a portion of a program is executed during a particular run, and how long
that portion takes to execute. The main purpose of profiling is to find the parts of your
program that can be improved to make the program run faster.
Activity 1.3a
Explain what is stored in a source file, an object file, and an executable file.
Examples of IDEs for C++ include: DEV C++, Code:Blocks, Microsoft Visual Studio,
Eclipse CDT(C/C++ Development Tooling), CodeLite IDE, Bluefish Editor, JetBrains
Clion. Figure 1.3 shows a screen from the DEV C++ IDE.
13
Figure 1.3: Screen from the DEV C++ IDE
Activity 1.3b
How can an IDE improve a programmer’s productivity?
14
Specification
A definition of what a computer program is expected to do. A statement of program
requirements. A formal statement of conditions against which the program can be verified.
There two types of requirements: functional and non-functional requirements.
Specification shows input requirements, output requirements, storage requirements and
processes that will turn input into output. This stage is for system analysts.
Design
Developing an algorithm for the proposed program. Programs use algorithms which are
like equations that tell the computer what task to perform. The aim of the programmer is
to create algorithms that are clear and simple. Algorithm is further broken down into
pseudo codes. Your design can also be presented using diagrams such as flowcharts. It
is a lengthy stage. This stage is for system designers.
Coding
After a program design, then an appropriate language is selected to write the program.
So coding is writing a program in a particular language such as C, C++, Java, Visual
Basic, etc. Coding languages differ in specifications and usability. It is translating a design
into appropriate programming language. It's possible that you might discover a design
error in the process of writing code. This stage is for system coders/programmers.
Testing
Now the program is created/developed. What is required is to check whether the program
meets the requirements (specification). Testing is the verification stage of whether the
program created meets the requirements. Any errors or deviation from the requirement
is uncovered at this stage. Testing is a debugging stage. To debug is to identify and
remove errors (bugs) from program. It is a lengthy and tedious stage. Once the
programmer locates the errors they are then fixed and the program is run again. This will
happen multiple times, often called “execute, check, and correct” until the program runs
flawlessly. Testing can be done by programmers, professional testers and even users.
This stage is for system testers.
15
Documentation
This stage is for writing supporting documents for the program for future references and
program readability. Documentation should be ongoing from the very beginning because
it is needed for those involved with program now and future. Different documents are
written:
• User documentation or user manuals for users of the program. It describes how to
use the system
• Programmer documentation for programmers. It is used as a reference for
maintaining / upgrading the program.
Activity 1.4
What is the meaning of ‘implementation of a program’?
Unit summary
In this Unit, you have covered the following main points:
• Computer program is a set of instructions that tells a computer(hardware) to do a
particular task.
• Computer programming is a process of writing set of instructions that tells a
computer (hardware) to do a particular task.
• Communication with a computer is done by using programming language.
Programming languages may be divided into three general types: machine
languages, assembly languages and high-level languages
• You learnt that all programming languages have the following things in common:
key words, programmer-defined identifiers, operators, punctuation and syntax.
• Programmers have a variety of tools available to enhance the software
development process. Some common tools include: editors, translators,
debuggers and profilers.
• Integrated Development Environments (IDEs) includes editors, debuggers, and
other programming aids in one comprehensive program.
16
• You learnt that program development process has the following stages:
specification, designing, coding, testing and documentation.
You have learnt what programming is all about and stages you can take to develop a
program. In the next unit we will look at how programs are written in C++.
17
UNIT
2 UNIT 2: INTRODUCTION TO C++ PROGRAMMING
Introduction
C++ is a widely used language because, in addition to the high-level features necessary
for writing applications it also has many low-level features. C++ is based on the C
language, which was invented for purposes such as writing operating systems and
compilers. C++ is also popular because of its portability. This means that a C++ program
can be written on one type of computer and then run on many other types of systems. In
this unit you will learn basic parts of a C++ program such as key words and punctuation,
C++ data types, how to define C++ variables, C++ assignment statements, constants and
comments.
Unit outcomes
By the end of this Unit, you must be able to:
• understand C++ program structure
• explain types of comments
• understand basic fundamental data types in C++
• define ‘variable’
• understand variable declaration and initialization
• define ‘constant variable’
• understand ways of declaring constants in C++ program
Key terms
Ensure that you understand the following key terms or phrases used in this unit:
procedural programming, object-oriented programming, standard header file, comment,
data type, variable, variable definition, variable declaration, variable initialization, identifier
and constant.
18
2.1 C++ Program Structure
Programs are written using different languages. C++ is an example a programming
language. There are generally two ways of writing programs
• Procedural programming
• Object-oriented programming
Procedural Programming
In procedural programming a program is a collection of procedures (functions). It is
procedure centered. Procedures are collections of programming statements that perform
a specific task.
Object-oriented programming
Object-oriented programming is centered on the object. An object is a programming
element that contain data and procedures that operate on the data. C++ can be used to
write both procedural and object-oriented programs.
19
General Structure of a Simple C++ Program
A C++ program has the following structure:
#include<iostream>
using namespace std;
int main()
{
.
.
.
return 0;
}
#include<iostream>
# indicates that this line is a preprocessor directive. Preprocessor reads the program
before it is compiled and only executes those lines beginning with # symbol. Preprocessor
is like a program that prepares/sets up your source code for the compiler. #include is
used to include the library or header file to your program. The header file to be included
is enclosed in <>. In our case iostream is a header file. The iostream library contains
routines that handle input and output (I/O) that include functions such as printing to the
display, getting user input from the keyboard, and dealing with files.
The header file contains codes that is added to your source code at the point the
#include appears. The result of this, is an enhanced source code (header file code plus
your source code). The header file such as iostream contains pre-written programming
codes that the program requires to work properly. iostream is a standard library also
called standard header file.
iostream (input/output stream) library (header file) contains actions for standard input
(getting data from a keyboard) and standard output (displaying data or information to a
monitor). Actions (objects) such as cout, cin and cerr are implemented in this file.
20
using namespace std;
Tells the compiler to use the std namespace. A namespace is grouping of variables,
classes, etc- (Concept of Object-oriented programming). Programs usually contain
various types of items with unique names. Variables, functions, and objects are examples
of program entities that must have names. C++ uses namespaces to organize the names
of program entities. The statement using namespace std; declares that the program will
be accessing entities whose names are part of the namespace called std.
The program needs access to the std namespace because every name created by the
iostream file is part of that namespace. In order for a program to use the entities in
iostream, it must have access to the std namespace. In C++, cout, cin, endl belong
to the namespace called std.
So, to use cout for example, we are required to indicate a namespace as well, so that
the compiler should know where to look for cout. The full name for cout can be
something like cout in std namespace (which is std::cout). To avoid writing long
names such as std::cout, the directive using namespace std; is used to inform
the compiler that whenever it sees short name such as cout, cin, it should check its
implementation in std namespace.
int main()
A C++ program is composed of functions. A function is a portion of program that does a
particular task. The C++ program has at least one function for it to work (run). This
function is called main() function. The main() function is the first function to be
executed in multi-function program. The word int stands for “integer.” It indicates that
the function sends an integer value back to the operating system when it is finished
executing. The int indicates that the main() function is expected to return an integer
number i.e. 0.
21
{…}
An opening brace or left-brace ({), it is associated with the beginning of the function main,
it marks the beginning of the function body (the function code). The closing brace (}),
marks the end of function.
return 0;
This line of code returns a number 0 when a program executes properly hence exits
normally. This sends the integer value 0 back to the operating system upon the program’s
completion. The value 0 usually indicates that a program executed successfully. If the
program does not execute properly i.e. exited abnormally, a different number either
positive or negative is returned. This line, return 0; returns an integer value because
the main() started with int (int main()).
Use of cout
cout is used to display the message (data) on a standard output device, monitor.
22
After writing the program with a text editor (IDE) and compiling it, you can run the program.
The program prints Welcome to C++ programming on the screen.
The body of our main function contains only one statement. This statement directs the
executing program to print the message Welcome to C++ programming on the screen.
A statement is the fundamental unit of execution in a C++ program. Functions contain
statements that the compiler translates into executable machine language instructions.
All statements in C++ end with a semicolon (;).
Note which lines in the program end with a semicolon (;) and which do not. Do not put a
semicolon after the #include preprocessor directive. Do not put a semicolon on the line
containing main, and do not put semicolons after the curly braces.
In the program, we are able to use short name cout without specifying its namespace
because of the directive using namespace std;. If that is removed, our program will
result in an error unless std:: included at the beginning of the cout.
23
2.1.2 Comments
A comment is text that the compiler ignores but that is useful to programmers. That means
you can type anything you want in your program and the compiler will never complain.
Most programs are much more complicated, comments help explain what’s going on in
that program or in that piece of code. It describes what a certain portion of code does or
how it is implemented. There are two types of comments:
• Single-line
• Block comments
Block comment
• Comments a line or a group of lines.
• Starts with a slash followed by an asterisk (/*)
• Ends with an asterisk followed by a slash (*/)
• Everything between these markers is ignored
• Example: /* this is a block comment */
Example
#include<iostream>
using namespace std;
int main()
{
// this is line comment
cout<<”comment example - inline”<<endl;
/*
this is
a block
comment
*/
cout<<“comment example – block”;
return 0;
}
24
Activity 2.1
Write a C++ program that will display your name on the screen, place a comment
with today’s date at the top of the program. Test your program by entering,
compiling, and running it.
The data we use every day is not of the same type. Some data values are numbers,
others are letters etc. How you manipulate these values is also different for instance for
numbers you can add them using a plus sign (+), but this is not so for letters. Even
numbers are not the same. Others are fractions while others are whole numbers. So, in
programming there is a need to know the type of the data values to be used in a program.
C++ is a statically typed language, meaning every variable must have a defined data type
before it is used. Data types specify the kind of data that can be stored and the operations
that can be performed on it.
25
C++ supports different types of data types, categorized as follows:
i. Primitive Data Types
ii. Derived Data Types
iii. User-Defined Data Types
Type Modifiers
Several of the basic types can be modified using one or more of these type modifiers:
• signed
• unsigned
• short
• long
26
Table 2.2: Type Modifiers
Modifier Description Example
signed Default for int (can store negative and signed int num;
positive values)
unsigned Stores only positive values unsigned int num;
27
The size of variables might be different from those shown in the above table, depending
on the compiler and the computer you are using. You can use the sizeof operator to
determine how large all the data types are on your computer.
The following code will produce correct size of various data types on your computer.
#include <iostream>
using namespace std;
int main()
{
cout<<"Size of char:" << sizeof(char)<< endl;
cout<<"Size of int:" << sizeof(int) << endl;
cout<<"Size of short int:"<< sizeof(short int)<< endl;
cout<<"Size of long int:" << sizeof(long int)<< endl;
cout<<"Size of float:" << sizeof(float)<< endl;
cout<< "Size of double:" << sizeof(double)<< endl;
cout<< "Size of wchar_t:" << sizeof(wchar_t)<< endl;
return 0;
}
The code above uses endl, which inserts a new-line character after every line. <<
operator is being used to pass multiple values out to the screen. When the code is
compiled and executed, it produces the result which can vary from machine to machine.
Type Casting
Type casting is the process of converting a variable from one data type to another. In
C++, type casting is commonly used when performing operations that involve different
data types or when a programmer wants to control how data is stored and processed.
28
• To control memory usage and precision
• To convert user input into required data types
Example:
#include <iostream>
using namespace std;
int main() {
int num = 10;
double result = num; // Implicit conversion from int to
double
return 0;
}
Advantages
• Automatic and easy to use
• No syntax required
• Safe when converting smaller types to larger types
Disadvantages:
• Can cause unexpected results in complex expressions
29
2. Explicit Type Casting (Manual Type Conversion)
Explicit type casting is performed manually by the programmer using a casting operator.
It is used when converting a larger data type to a smaller data type or when precision
control is needed. This is also called Type Demotion.
Example:
#include <iostream>
using namespace std;
int main() {
double num = 10.99;
int result = (int)num; // Explicit conversion from double to int
cout << "Original double value: " << num << endl;
cout << "Converted integer value: " << result << endl;
return 0;
}
Advantages:
• Full control over data conversion
• Prevents logical errors
Disadvantages:
• May cause data loss
• Requires programmer responsibility
The main derived data types include Arrays, Pointers, and References.
30
1. Arrays
An array is a collection of multiple variables of the same data type stored in contiguous
memory locations.
Example:
int marks[5];
marks is an array that can store 5 integer values. Each element is accessed using an
index (starting from 0).
2. Pointers
A pointer is a variable that stores the memory address of another variable.
Example:
int* ptr;
ptr is a pointer to an integer. It can store the address of an integer variable.
Example Usage:
int num = 10;
int* ptr = # // ptr stores address of num
3. References
A reference is an alias (another name) for an existing variable. It does not store a
separate value but refers directly to the same memory location.
Example:
int& ref = num;
ref is a reference to num. Any change to ref also changes num.
Example:
ref = 20; // num also becomes 20
31
[Link] User-Defined Data Types
User-defined data types are data types that are created by programmers (users) to
represent complex data in a meaningful way. They help in organizing data logically and
supporting Object-Oriented Programming (OOP) concepts.
1. Structure (struct)
A structure is used to group related variables of different data types under a single
name.
Example:
struct Student {
int id;
char name[20];
float marks;
};
Student is a structure that stores student ID, name, and marks. Each variable inside
the structure is called a member.
2. Class (class)
A class is a blueprint or template used to create objects. It contains data members
(variables) and member functions (methods).
Example:
class Student {
public:
int id;
float marks;
void display() {
cout << id << " " << marks;
}
};
The class defines the properties and behaviors of objects. Objects are created from the
class.
32
3. Enumeration (enum)
An enumeration is a user-defined data type that consists of a set of named constant
values.
Example:
Color is an enum type with three constant values: RED, GREEN, and BLUE. Each
name represents an integer value starting from 0 by default.
Example Usage:
Color c = RED;
Activity 2.2a
Which integer data types can only hold non-negative values?
2.2.2 Variables
Variable is a location of a memory identified by a name whose content can change.
Variables represent storage locations in the computer’s memory. A variable is a container
which hold values in programming. Each variable (and its content) is accessed by a
name. The name of the variable is also called identifier. A variable has Name, Value
and Address.
Definitions:
Variable Definition: - Variable definition is the place where the variable is created. It is
allocated storage in the computer memory. It tells the compiler the variable’s name and
the type of data it will hold. The data type is written first, followed by the name of the
variable.
Variable Declaration: - Variable declaration is the place where nature (type) of variable
is stated, but no space is allocated.
33
Variable Initialization: - Variable initialization means assigning a value to the variable.
Variables can be created many times, but defined only once. Memory space is not
allocated for a variable while declaration, it happens only on variable definition. You must
have a definition for every variable you use in a program. In C++, a variable definition can
appear at any point in the program as long as it occurs before the variable is ever used.
Variable Declaration
To put a variable into existence is called variable declaration. Variable declaration is
requesting Operating System to prepare a part of memory to be used for storing program
data.
For example;
int age;
This declares a variable of data type integer whose identifier/name is age. This variable’s
name is age. The word int stands for integer, so age may only be used to hold integer
numbers.
You can declare variables of the same data types in one statement as shown below:
In general:
data_type variable_name1, variable_name2;
For example;
int height, mass;
This declares variables of data type integer whose identifiers/names are height and
mass.
34
Initializing Variables
When variable is declared (created), it can now be assigned a value. A variable can be
assigned a value as:
variable_name = value; // assuming variable_name is declared
For example,
age = 20;
This is called an assignment statement and the = sign is called the assignment
operator. This operator copies the value on its right (20) into the variable named on its
left (age). This line does not print anything on the computer’s screen. It runs silently
behind the scenes, storing a value in RAM. After this line executes, age will be set to 20.
The item on the left hand side of an assignment statement must be a variable. It would
be incorrect to say 20 = age;
You may use a single statement to declare the variable and assign a value to it:
data_type variable_name = value;
For example;
float height = 1.62;
This declares variable of data type float whose identifier/name is height and initialized
to 1.62.
Initializing a variable also called initiating a variable is giving the variable an initial (a
starting value). This is usually done at declaration. They are three ways to initialize
variables at declaration in C++:
i. Using =
For example; int age = 20;
ii. Using ( )
For example; int (20);
iii. Using { }
For example; int {20};
35
If you don’t explicitly initialize numeric data types such as int, float, double, variable is
implicitly initialized to zero (0).
For example:
int age; //same as int age = 0;
cout<<age; //Displays 0.
36
The prompt should ask the user a question, or tell the user to enter a specific value. For
example, the code displays the following prompt:
enter your age:
Activity 2.2b
Write declaration statements to declare integer variables i and j and float
variables x and y. Extend your declaration statements so that i and j are both
initialised to 1 and y is initialised to 10.0.
2.2.3 Constants
Constant is a location of a memory identified by a name whose content cannot change.
A constant is a variable with unchangeable content. Used to keep content that should
not change at any point in a program. Also called constant variable.
Constant Declaration
A constant can be declared in two ways in C++:
i. Using #define
• Placed soon after #include… directives.
• Syntax:
#define CONSTANT_NAME VALUE
• Example:
#define HEIGHT 1.4
Constant names should always be in block letters to distinguish them from variable
names.
37
Example:
#include<iostream>
#define PI 3.14 //first constant using #define
using namespace std;
int main()
{
const float HEIGHT=1.4; //second constant using const keyword
cout<<PI<<endl;
cout<<HEIGHT;
return 0;
}
38
iv. Variable name should be unique in the program.
• You should always choose names for your variables that give an
indication of what the variables are used for
39
Entering Multiple Values
You can use cin to input multiple values at once. cin will also read multiple values of
different data types.
Example;
int whole;
double fractional;
char letter;
cin statement to read all those values:
cin >> whole >> fractional >> letter;
Note that the values are stored in the order entered in their respective variables.
Escape sequence
Escape sequences are written as a backslash character (\) followed by one or more
control characters and are used to control the way output is displayed. There are many
escape sequences in C++.
40
• \n is newline escape sequence. It causes the cursor to go to the next line for
subsequent printing.
• \t is Horizontal tab. It causes the cursor to skip over to the next tab stop.
Activity 2.2c
Assume value is an integer variable. If the user enters 3.14 in response to
the following programming statement, what will be stored in value?
cin >> value;
Unit summary
In this Unit, you have covered the following main points:
• Programs are written using different languages like C++, two ways of writing
programs are Procedural Programming and Object-Oriented Programming.
• You learnt and discussed parts of a C++ program: #include<iostream> ,
using namespace std;, int main(), { }, return 0; and use of cout in
conjunction <<.
• A comment is text that the compiler ignores but useful to programmers and there
are of two types: Single-line and Block comments
• Variables are reserved memory locations to store values. Variables are classified
according to their data type, which determines the kind of information that may be
stored in them.
• Variable is a location of a memory identified by a name whose content can change
while constant is a location of a memory identified by a name whose content cannot
change.
You have learnt the structure of a C++ program and how to declare variables in a C++
program. In the next unit we will look at programming statements that result a value as
well as value computation.
41
UNIT
3 UNIT 3: OPERATORS AND EXPRESSIONS
Introduction
This unit uses the C++ numeric types introduced in unit 2 to build expressions and perform
arithmetic operations. C++ allows you to construct complex mathematical expressions
using multiple operators and grouping symbols. In this unit you will learn program
statements, operators, expressions such as arithmetic expressions, relational
expressions, logical expressions, and conditional expression. You will also learn
precedence and associativity rules when two operators compare for the same operand.
Unit outcomes
By the end of this unit, you must be able to:
• understand program statements
• explain types of expressions
• describe ways to classify operators
• evaluate expression based on rules of precedence and associativity
• explain types of program errors
Key terms
Ensure that you understand the following key terms or phrases used in this unit: program
statement, expression statement, Operator, Operand, Literal expression, Variable
expression, Arithmetic expression, assignment statement, Lvalue and Rvalue.
42
programming language has a set of basic statements to manipulate data (read, write and
transform). A program consists of a combination of data and statements to perform some
tasks. A program can become a new statement (function) that can be used in other
programs.
int main()
{
int n = 1; // declaration statement
n = n + 1; // expression statement
cout << "n = " << n << “\n”; // expression statement
return 0; // return statement
}
i. Expression statements
An expression followed by a semicolon is a statement. Most statements in a typical
C++ program are expression statements, such as assignments or function calls. An
expression statement without an expression is called a null statement. It is often used
to provide an empty body to a for or while loop. It can also be used to carry a label
in the end of a compound statement.
43
if (x > 5) // start of if statement
{ // start of block
int n = 1; // declaration statement
cout << n; // expression statement
} // end of block, end of if statement
v. Iteration statements
Iteration statements repeatedly execute some code.
• while loop;
• do-while loop;
• for loop;
44
vii. Declaration statements
Declaration statements introduce one or more identifiers into a block:
int num1, num2;
int num = 1;
Activity 3.1
Is the variable x a valid C++ expression?
2x – 3 = 1
Expression
Figure 3.1: Mathematical expression
45
3.2.1 Operators and Operands
Operator: - An operator is a symbol that operates on a value or variable to compute some
task.
Operand: - An operand is a value or variable which gets operated by an operator.
The operations (specific task) are represented by operators and the objects of the
operation(s) are referred to as operands. Some examples of expression:
i. Literal expression
• Example: 2, “A+”,’B’
• Value: The literal itself
46
An expression in C++ is any valid combination of operators, constants and variables.
The expression in C++ can be of any type i.e. relational, logical etc. Type of operators
used in an expression determines the type of expression.
General Usage:
operand1 operator operand2
For example:
4+3; this yields 7 when executed.
cout<<4+3;
Here 4 and 3 are operands and + is operator.
x = 6 * 7;
cout << x; // this output 42
Arithmetic operator: %
The modulus (remainder) Operator. It computes the remainder after the first operand is
divided by the second.
47
For example:
5 % 2 = 1
6 % 2 = 0
When converting some algebraic expressions to C++, you may have to insert
parentheses that do not appear in the algebraic expression.
48
Table 3.2: Algebraic and C++ Expressions
Algebraic Expression C++ Expression
𝒙 y = x / 2 * 3;
Y=3𝟐
z = 3bc + 4 z = 3 * b * c + 4;
Activity 3.2a
Write C++ expressions for the following algebraic expression:
𝟒𝒙+𝟐
b =
𝟓𝒂−𝟏
b. Division of integer and real number or real numbers only evaluates to real
number
Real/Integer = Real
OR
Integer/Real = Real
OR
Real/Real =Real
Example:
cout<<(22.0/7); //displays 3.1415…
cout<<(1/2.0); //displays 0.5
49
Lvalue and Rvalue
Consider the following statements:
1. x = 3;
2. 3 = x;
3. y = x+2;
Which statements are valid in C++?
• The first (1) and last (3) statement are valid
o Second (2) its invalid in C++, constants such as 3 cannot be used on the
left side of the assignment statement.
Lvalue
• Lvalue is value that can be on either side of the assignment statement.
• Variables are Lvalues (x in first and last statements above).
Rvalue
• Rvalue is a value that should only appear on the right-hand side of the assignment
statement.
• All constants (numbers, letters etc.) are Rvalues.
Activity 3.2b
Assume the following variable definitions:
int a = 5, b = 12;
double x = 3.4;
a = b = c = d = 12;
50
The value 12 will be assigned to each variable listed in the statement. This works
because the assignment operations are carried out from right to left. First 12 is assigned
to d. Then d’s value, now a 12, is assigned to c. Then c’s value is assigned to b, and
finally b’s value is assigned to a.
Activity 3.2c
Write a multiple assignment statement that assigns 46 to the variables total,
subtotal, tax, and shipping.
The expression on the right side of the assignment operator gives the value of number
plus 1. The result is then assigned to number, replacing the value that was previously
stored there. Effectively, this statement adds 1 to number.
Because these types of operations are so common in programming, C++ offers a special
set of operators designed specifically for these jobs. The combined assignment operators
do not require the programmer to type the variable name twice. Table 3.3 shows the
combined assignment operators, also known as compound operators or arithmetic
assignment operators.
51
Activity 3.2d
Write statements using combined assignment operators to perform the following:
a. Divide total by 27.
b. Subtract discount times 4 from total
Notice the equality operator is two = symbols together. Don’t confuse this operator with
the assignment operator, which is one = symbol. The == operator determines if a variable
is equal to another value, but the = operator assigns the value on the operator’s right to
the variable on its left.
Activity 3.2e
Assuming x is 5, y is 6, and z is 8, indicate whether each of the following relational
expressions is true or false:
a. x == 5
b. 7 <= (x + 2)
c. z > 9
d. (2 + x)!= y
52
iii. Logical Expressions
These are truth expressions. They have True (T) or False (F) as operands. The result
from logical expression is a Boolean value (True or False). Mostly these operands are
evaluated from the relational expressions. Logical operators connect two or more
relational expressions into one or reverse the logic of an expression. Logical operators
in C ++ are:
• && (AND operator: e.g. T && T)
• || (OR operator: e.g. T || F)
• ! (NOT or negation operator: e.g. ! T)
The truth table lists all the possible combinations of values that two expressions may
have, and the resulting value returned by the && operator connecting the two
expressions. Table 3.4 shows a truth table for the && operator
If the sub-expression on the left side of an && operator is false, the expression on the
right side will not be checked. Because the entire expression is false if even just one of
the sub-expressions is false, it would waste CPU time to check the remaining expression.
This is called short circuit evaluation.
53
Example:
The || operator also performs short circuit evaluation. If the sub-expression on the
left side of an || operator is true, the sub-expression on the right side will not be checked.
Because it is only necessary for one of the sub-expressions to be true for the whole
expression to evaluate to true, it would waste CPU time to check the remaining
expression.
54
Example:
if a=3, b=4, c=-2
1) a == 3 || b>c; //This evaluates to true since both conditions hold
2) a<0 || b>a; /*First condition evaluates to false and the second one
to true. The final result will be true */
3) a==2 || c>0;/* Both conditions don’t hold hence the final result will
be false */
Logical Expressions – NOT Operator
• NOT(!) negates the result of relational expression.
• In other words, it negates the Boolean result.
• True become False. False becomes True
It takes an operand and reverses its truth or falsehood. In other words, if the expression
is true, the ! operator returns false, and if the expression is false, it returns true. Table 3.6
shows a truth table for the ! operator.
Example:
if a=3;
1) ! a == 3; //This evaluates to false since condition holds
2) ! a < 0; //This condition evaluates to true since condition does not hold
Activity 3.2f
If a = 2, b = 4, and c = 6, indicate whether each of the following conditions is true
or false:
a. (a == 4) || (b > 2)
b. (1 != b) && (c != 6)
55
iv. Conditional Expression
• An expression that conditionally operates on its operand.
• It has three operands
➢ The first operand is a condition (relational expression)
➢ The second operand is expression to be evaluated if condition (1st
operand) is true.
➢ The third operand is expression that is evaluated when condition is
false
• Conditional operator is ?:
• General syntax is:
operand1 ? operand2 : operand3
x < 0 ? y = 10 : z = 20;
2nd expression:
executes if the
condition is true
You can also put parentheses around the sub-expressions, as shown below:
(x < 0) ? (y = 10) : (z = 20);
Example:
if a = 3
1) a==3 ? x = 1 : x = 0; //This evaluates x=1 since a==3 is true
2) a!=3 ? x = 1 : x = 0; //This evaluates x=0 since a!=3 is false
56
You can use the conditional operator to create short expressions that work like if/else
statements. It provides a shorthand method of expressing a simple if/else statement.
The part of the conditional expression that comes before the question mark is the
condition to be tested. It’s like the expression in the parentheses of an if statement. If the
condition is true, the part of the statement between the ? and the : is executed.
Otherwise, the part after the : is executed. The statement below:
a==3 ? x = 1 : x = 0;
if(a==3)
{
x=1;
}
else
{
x=0;
}
a==3 ? x = 1 : x = 0;
operand2 (x=1) and operand3 (x=0) are assigning values to a variable x; So, the above
statement can also be written as below:
x = a==3 ? 1: 0;
Activity 3.2g
Rewrite the following conditional expressions as if/else statements.
factor = x >= 10 ? y * 22 : y * 35;
57
Other Operators
a. Assignment operator (=)
• Assigns values to variables
• Example:
➢ num = 3; (assigns 3 to variable num)
➢ a = a + b is the same as a += b
b. Increment operator (++).
• Takes one operand
• Example:
➢ if num = 1
num++; // evaluates to 2;
num++ is the same as num = num + 1
c. Decrement Operator (--)
• Takes one operand
• Example:
➢ if num = 1;
num--; //evaluates to 0;
num-- is the same as num = num - 1
Unary Operators
• Operate on one operand (require one operand)
• Examples include:
➢ Not operator (!)
➢ Increment operator (++)
➢ Decrement operator (--)
Binary Operators
• Operate on two operands (require two operands)
• Examples include:
➢ Arithmetic operators (+,-,*,/,%)
➢ Relational operators (==,>,<,>=,<=,!=)
➢ Logical operators (&&,||)
58
Ternary Operators
• Operate on three operands (require three operands)
• Examples include:
➢ Conditional operator (? :)
C++ solves this problem by assigning priorities to operators, operators with high priority
are then evaluated before operators with low priority. Operators with equal priority are
evaluated in left to right order.
When two operators compare for the same operand. The rules of precedence specify
which operator wins. The operator with the higher precedence wins. If both competing
operators have the same precedence, then the rules of associativity determine the
winner. Associativity is the order in which an operator works with its operands.
Associativity is either left to right or right to left. The priorities of the operators in high to
low priority order:
!
Higher Precedence
*/%
+-
< <= >= > Associativity: Execute left to right
(Expect for = and unary-)
== !=
&&
||
=
Lower Precedence
59
If you are confused, then use parentheses () in your code. Expressions within
parentheses are evaluated first.
Activity 3.3
If a = 2, b = 4, and c = 6, is the following expression true or false?
(b > a) || (b > c) && (c == 5)
i. Syntax Errors
Violation of the grammar rules of the language. Discovered by the compiler (Error
messages may not always show correct location of errors). A compile-time error
results from the programmer’s misuse of the language.
Syntax error is a mistake in the grammar of a language, for example C++ requires
that each statement should be terminated by a semi-colon. If you miss this semi
colon out then the compiler will signal a syntax error. Before proceeding any
syntax, errors are corrected and compilation is repeated until the compiler
produces an executable program free from syntax errors.
60
ii. Run-time errors
Error conditions detected by the computer at run-time. A run-time error will cause
the program to halt during execution because it cannot carry out an instruction.
Typical situations which lead to run-time errors are attempting to divide by a
quantity which has the value zero or attempting to access data from a non-existent
file.
The compiler ensures that the structural rules of the C++ language are not violated.
It can detect, for example, the malformed assignment statement and the use of a
variable before its declaration. Some violations of the language cannot be detected
at compile time, however. A program may not run to completion but instead
terminate with an error. We commonly say the program “crashed”.
Beginning programmers tend to struggle early on with compile-time errors due to their
unfamiliarity with the language. The compiler and its error messages are actually the
programmer’s best friend. As the programmer gains experience with the language and
the programs written become more complicated, the number of compile-time errors
decrease or are trivially fixed and the number of logic errors increase
Errors that escape compiler detection (run-time errors and logic errors) are commonly
called bugs. Since the compiler is unable to detect these problems, such bugs are the
major source of frustration for developers.
61
Compiler Warnings
A warning issued by the compiler does not mark a violation of the rules in the C++
language, but it is a notification to the programmer that the program contains a construct
that is a potential problem.
Activity 3.4
i. When the program is running it produces a number that is too large to fit
into the space allocated for it in memory. What type of error is this?
ii. A program runs without any errors being reported but outputs result that
are wrong, what type of error is likely to have caused this?
Debugging is when you're the detective trying to find the culprit—the bug. It's like a puzzle
where you follow clues (error messages, unexpected behaviour) to figure out what went
wrong. Some tools and practices can make this process smoother, like using a debugger
to step through your code and inspect variables.
Testing doesn't prove the absence of bugs; it only shows their presence. So, writing good
tests is crucial. And when bugs inevitably appear, don't panic. Take a systematic
approach to debugging, and you'll be back on track in no time.
62
3.5.1 Program Testing
Program Testing is the process of executing a program with the intent of finding errors.
Involves running the program with various inputs to ensure it behaves as expected.
Program testing offers numerous benefits that contribute to the overall quality and
reliability of software:
➢ Error Detection: Testing helps identify and detect errors or bugs in the code. Early
detection allows programmers to address issues before they escalate, reducing
the cost and effort required for fixing errors later in the development process.
➢ Improved Software Quality: Rigorous testing ensures that the software meets
specified requirements and functions as intended. High-quality software is more
reliable, leading to increased user satisfaction and trust in the product.
➢ Enhanced Security: Security testing helps identify vulnerabilities and
weaknesses in the software. Addressing security issues early in the development
process is crucial for creating secure software and protecting sensitive data.
➢ Compliance with Standards: Testing ensures that the software complies with
industry standards and regulations. Helps meet legal requirements, security
standards, and industry best practices.
➢ Cost-Effective Bug Fixing: Fixing bugs during the testing phase is generally more
cost-effective than addressing issues discovered in later stages or after the
software is deployed.
63
- Helps catch errors early in the development process.
- Example:
✓ Testing a specific function that performs a mathematical
operation.
64
3.5.2 Program Debugging
Debugging is the process of identifying and fixing errors or bugs in a program. It requires
analyzing the code to locate and resolve issues. Debugging is a crucial process in
software development that involves identifying and fixing errors or bugs in a program. The
following are advantages of debugging:
65
1. Print Statements
- Insert print statements in the code to output variable values or execution
progress.
- Simple and effective for identifying the flow of execution.
- May clutter the code and need to be removed after debugging.
- Example: Printing the values of variables at key points in the code.
2. Interactive Debuggers
- Employ integrated development environments (IDEs) with debugging tools.
- Provides detailed insights into the program's execution.
- Requires familiarity with the debugger's features.
- Example: Setting breakpoints, inspecting variable values, and stepping through
code.
4. Code Review
- Have another programmer review the code.
- Fresh perspective may identify issues overlooked by the original programmer.
- Relies on the availability and expertise of another person.
- Example: Sharing the code with a colleague for a fresh perspective.
Activity 3.5
What practices should be adopted for effective program testing and debugging
in software development?
66
Unit summary
In this Unit, you have covered the following main points:
• Statements are fragments of the C++ program that are executed in sequence. In
C++, any expression followed by a semicolon is a statement.
• C++ has following types of statements: expression statements, compound
statements, labeled statement, selection statements, iteration statements, jump
statements, declaration statements and try blocks
• An expression statement is a statement that result a value. A sequence of
operators and their operands, that specifies a computation.
• Operators can be classified according to the type of their operands and of their
output as well as the number of their operands.
• When two operators compare for the same operand. The rules of precedence
specify which operator wins, if both competing operators have the same
precedence, then the rules of associativity determine the winner.
• You learnt that programming error falls under one of three categories: syntax errors
run-time errors or logic errors (warning).
• Program testing ensures software functions as intended, while debugging
identifies and rectifies errors to enhance code quality and reliability in software
development.
You have learnt programming operators and expressions. In the next unit we will look at
different techniques you can use to solve a problem. The unit will describe program design
phase which shows the steps that should be taken in order to build a program that meet
requirements.
67
UNIT
4 UNIT 4: PROGRAM DESIGN
Introduction
Programming is a process of problem solving. Different people use different techniques
to solve problems. Some techniques are nicely outlined and easy to follow. They not only
solve the problem, but also give insight into how the solution was reached. To be a good
problem solver and a good programmer, you must follow good problem-solving
techniques. One common problem-solving technique includes analyzing a problem,
outlining the problem requirements, and designing steps, called an algorithm, to solve the
problem.
After program requirements are clearly stated in terms of input, output, process and
storage, the next stage is to come up with a blue-print of the program you intend to build.
Program design phase shows the steps that should be taken in order to build a program
that meet requirements. This unit covers algorithm notations such as natural language,
pseudo code and flowcharts, program requirements gathering and then translating the
algorithm into a programming language.
Unit outcomes
By the end of this Unit, you must be able to:
• Explain basic types of statements
• Define algorithm
• Understand different algorithm notations
• Develop pseudocode and flowcharts
Key terms
Ensure that you understand the following key terms or phrases used in this unit: program
statement, algorithm, pseudocode, flowcharts, terminal and flowline.
68
4.1 Program Statements
Program Design
Program design refers to the process of planning, structuring, and organizing a computer
program before writing the actual code. It involves thinking about what the program will
do, how it will do it, and how it will be structured.
1. Problem Definition
This is the first step where the programmer clearly understands and defines the
problem.
69
Activities:
• Identify what the program must do
• Understand user requirements
• Determine constraints and limitations
Tools Used:
• Algorithms
• Flowcharts
• Pseudocode
Purpose:
To create a step-by-step solution before coding.
3. Coding
• This is the process of writing the actual program using a programming language
such as C++.
Activities:
• Writing source code
• Using variables, control structures, functions, and classes
70
Types of Errors:
• Syntax errors
• Logical errors
• Runtime errors
Inputs Required
• These are the data provided to the program.
• Examples: Student marks, numbers, names, file data.
Processing Logic
• These are the operations performed on the input data.
• Examples: Calculations, sorting, decision-making, loops.
Expected Outputs
• These are the results produced by the program.
• Examples: Total marks, grades, reports, messages.
71
Program Statements
A program statement is a small unit of code with a complete programing thought i.e. that
makes sense. It is a sentence of programming language. Ends with semicolon (;) in many
languages such as C++, Java, PHP.
i. Declaration Statements
a. Statements for declaring variables/constants
• Specifies data type and a name of the variable
• Example: int age;
b. Statements for declaring functions
• Specifies return value data type, function name and list of parameters.
• Example: float average(int a, int b); (To be covered in Unit 6)
b. Output Statements
• Output Statements send data to output device or file
• In C++, cout<< is used to send data (information) to a standard output device
such as a monitor.
• Example:
cout<<“Enter your age=> ”;// This sends data from program to monitor
72
iii. Assignments Statements
• Statements for copying /setting values (data) to variables
o Equals sign (=) is used in assignment statement
o A variable where data is copied/set to is on the left side of the equals
sign (=)
o On the right side of equals sign (=) is a valued to be copied/set. This can
be a literal value, another variable or an expression.
• Examples:
o Literal value: age = 20; // This copies/sets 20 to variable age.
o Another variable: number2 = number1;/* This copies value of
variable number1 to variable number2.*/
o Expression: sum = number1 + number2;/*This copies result of
calculation of number1 + number2 to variable sum.*/
Activity 4.1
How would you consolidate the following variable declaration statement and
assignment statement into a single statement?
int apples;
apples = 20;
73
In a programming environment, the problem-solving process requires the following three
steps:
i. Analyze the problem, outline the problem and its solution requirements, and design
an algorithm to solve the problem.
ii. Implement the algorithm in a programming language, such as C++, and verify that
the algorithm works.
iii. Maintain the program by using and modifying it if the problem domain changes.
To develop a program to solve a problem, you start by analyzing the problem. You then
design the algorithm; write the program instructions in a high-level language, or code the
program; and enter the program into a computer system.
Analyzing the problem is the first and most important step. This step requires you to do
the following:
1. Thoroughly understand the problem.
2. Understand the problem requirements. Requirements can include whether the
program requires interaction with the user, whether it manipulates data, whether it
produces output, and what the output looks like.
If the program manipulates data, the programmer must know what the data is and
how it is represented. That is, you need to look at sample data. If the program
produces output, you should know how the results should be generated and
formatted.
3. If the problem is complex, divide the problem into subproblems and repeat Steps
1 and 2. That is, for complex problems, you need to analyze each subproblem and
understand each subproblem’s requirements.
1. Input
• An algorithm should accept zero or more inputs.
74
• Inputs are the data values that the algorithm processes.
• Example:
o A program that calculates student grades may take marks as input.
2. Output
• An algorithm must produce at least one output.
• The output is the result after processing the input.
• Example:
o The final grade (A, B, C) is the output.
3. Definiteness
• Each step of the algorithm must be clearly and precisely defined.
• There should be no ambiguity in instructions.
• Example:
o Instead of saying “process the data”, say “calculate the average of marks”.
4. Finiteness
• The algorithm must terminate after a finite number of steps.
• It should not run forever.
• Example:
o A loop must have a stopping condition.
5. Effectiveness
• Each step should be simple, practical, and executable within a reasonable
time.
• Example:
o Using simple arithmetic operations rather than complex or impossible
instructions.
6. Generality
• The algorithm should work for all valid inputs, not just a single case.
• Example:
o A sorting algorithm should sort any list of numbers, not only one specific
list.
75
Steps in Algorithm Design
Designing an algorithm involves a systematic process:
Activities:
• Identify the inputs (e.g., student marks, numbers).
• Identify the outputs (e.g., total, average, grade).
• Determine the processing logic (calculations, decisions, loops).
• Consider edge cases such as:
o Negative numbers
o Very large values
o Empty input
Example Steps:
1. Read marks
2. Calculate total
3. Compute average
4. Display results
Example:
START
READ marks
CALCULATE average
DISPLAY average
END
76
Step 4: Represent the Algorithm as a Flowchart
• A flowchart is a graphical representation of an algorithm using standard symbols
such as:
o Oval – Start/End
o Parallelogram – Input/Output
o Rectangle – Processing
o Diamond – Decision
Flowcharts help visualize the program logic.
Example:
cout << "Enter marks: ";
cin >> marks;
average = marks / 2;
cout << average;
Characteristics:
o Very simple to understand
o Inefficient for large problems
Examples:
o Linear Search
o Bubble Sort
77
Examples:
o Merge Sort
o Quick Sort
o Binary Search
3. Dynamic Programming
• Breaks a problem into overlapping subproblems and stores the results to
avoid recomputation.
Applications:
o Fibonacci sequence
o Shortest path problems
o Knapsack problem
4. Greedy Algorithm
• Makes the best local decision at each step hoping to reach the global
optimal solution.
Examples:
o Prim’s algorithm
o Kruskal’s algorithm
o Coin change problem
5. Backtracking
• Tries all possible solutions but eliminates invalid ones early (pruning).
Examples:
o N-Queens problem
o Sudoku solver
o Maze solving
78
i. Problem solving phase
• Result is an algorithm that solves the problem
For an algorithm to be suitable for computer use it must possess various properties:
a. Finiteness
• The algorithm must terminate after a finite number of steps.
b. Non-ambiguity
• Each step must be precisely defined.
c. Effectiveness
• This basically means that all the operations performed in the algorithm can
actually be carried out, and in a finite time.
79
Activity 4.2
What is a program design?
Example: Write an algorithm for a program that accepts two numbers and displays their
sum.
Solution:
80
Terms used in pseudocode algorithm
a. Declaration statement
• USE VARIABLES: list-of-variables As data-type
• Example: VARIABLE: age, grade As Integer // (which in C++
is int age, grade;)
OR
• USE VARIABLES: list-of-variables DataType data-type
• Example: USE VARIABLE: age, grade of DataType Integer
// (which in C++ is int age, grade;)
b. Output Statement
• DISPLAY message
•Example: DISPLAY “Enter your age”
//(which in C++ is cout<<“Enter your age”;)
d. Input Statement
• GET variable-name
• Example: GET age //(which in C++ is cin>>age;)
e. Assignment Statement
• COMPUTE expression
• Example: COMPUTE sum = number1 + number2
//(which in C++ is sum = number1 + number2;)
You do not necessarily need to use COMPUTE for assignment statements that do not
involve arithmetic expressions such as age = 20;
Example: Write a pseudocode for a program that accepts two numbers and displays their
sum.
Solution:
BEGIN
USE VARIABLES: num1, num2, sum As Real
DISPLAY “Enter first number”
GET num1
DISPLAY “Enter second number”
GET num2
COMPUTE sum = num1 + num2
DISPLAY “Sum of two numbers is”, sum
END
81
4.3.3 Algorithm by Flowcharts
A flowchart is a graphical expression of an algorithm. It graphically shows how the steps
are related to each other. It’s a Diagram that shows the logical flow of a program. There
are many symbols used in drawing a flowchart. The final visualization can then be easily
translated into a program. Table 4.1 show symbols used in flowchart:
82
Example: Draw a flowchart for a program that accepts two numbers and displays their
sum.
START
GET num1
GET num2
DISPLAY sum
END
Figure 4.1: Flowchart for a program that sum two given numbers
Activity 4.3
How are flowcharts used in computer programming?
83
4.4 IPO Model
The IPO (Input-Process-Output) model is a fundamental concept in program design.
The IPO Model is a conceptual framework for understanding systems, processes, and
problem-solving. It describes how inputs are transformed through processes to produce
outputs. This model is widely used in software development, system design, and
organizational workflows.
IPO Model provides a structured approach to solving problems by dividing the task into
three key stages:
ii. Process: Manipulating the input data to perform calculations, apply logic,
or execute algorithms.
2. Process
• The processing stage applies logic, performs calculations, or manipulates data
based on the program’s requirements.
• C++ provides tools for processing, including:
o Arithmetic and logical operators.
o Control structures like loops and conditional statements.
o Functions for modularizing code.
84
3. Output
• The output stage displays results to the user or stores them for later use.
• In C++, output is commonly handled using:
o Standard output streams like cout.
o File handling mechanisms using ofstream.
o External systems or devices.
Problem Statement:
Design a program that calculates the average grade of a student based on their
scores in three subjects.
Solution:
Step 1: Input
• Input three subject scores from the user.
Step 2: Process
• Calculate the average of the scores.
Step 3: Output
• Display the average grade.
85
Code Implementation:
#include <iostream>
using namespace std;
int main() {
// Input: Declare variables to store scores
double score1, score2, score3;
return 0;
}
86
3. Scalability:
- Allows for easier program expansion by adding new functionalities to
specific stages.
4. Debugging:
- Simplifies troubleshooting by isolating issues to a particular stage.
1. Software Development:
- Designing algorithms, flowcharts, and programs.
2. Business Processes:
- Streamlining workflows by identifying inefficiencies in inputs or
processes.
3. Engineering:
- Modeling systems like manufacturing pipelines or electrical circuits.
4. System Analysis and Design:
- Analyze existing systems and design new ones by visualizing data flow
5. Data Processing:
- Integral in data analytics and database management
The IPO model is a powerful framework for designing efficient and well-structured
programs in C++. By dividing the program into input, process, and output stages,
developers can create robust solutions to complex problems. The model promotes clarity,
modularity, and maintainability in program design.
Activity 4.4
How does the IPO model contribute to problem-solving in software development?
87
Unit summary
In this Unit, you have covered the following main points:
• A program statement is a small unit of code with a complete programing thought.
In C++ there are three basic types of statements: declaration statements, input /
output statements and assignments statements.
• Algorithm is a step-by-step problem-solving process in which a solution is arrived
at in a finite amount of time.
• Program design process has problem solving phase and implementation phase
• An algorithm can be expressed in a natural language, pseudo code and flowcharts
– design phase and programming language – coding phase.
• The IPO model is a powerful framework for designing efficient and well-
structured programs.
• The IPO model promotes clarity, modularity, and maintainability in program
design.
You have learnt program design as a programming stage and different notations which
you can use to express your program algorithm. In the next unit we will look at program
control structures which determines how execution of the program should flow.
88
UNIT
5 UNIT 5: PROGRAM CONTROL STRUCTURES
Introduction
All the programs in the preceding unit execute exactly the same statements regardless of
the input, if any, provided to them. They follow a linear sequence: Statement 1,
Statement 2, etc. until the last statement is executed and the program terminates.
Linear programs like these are very limited in the problems they can solve. There are
cases where a program has to make a decision on whether to execute a certain piece of
code or not. There are times where certain piece of code for the program may be required
to be executed repeatedly.
This unit introduces constructs that allow program statements to be optionally executed,
depending on the context (input) of the program’s execution. Should the program
execution be line by line for every line from top to bottom of the program? Should it jump
some lines of code upon fulfilment of certain conditions? Should other lines of codes be
executed repeatedly?
Unit outcomes
By the end of this Unit, you must be able to:
• Define ‘program control structure’
• Explain types of program control structures
• Understand Sequential program control structures
• Explain forms of selection program control structures
• Explain forms of Loop program control structures
Key terms
Ensure that you understand the following key terms or phrases used in this unit: program
control structures, condition, IF Statement, SWITCH statement, Pre-condition, Post-
condition and Infinite loop.
89
5.1 Program Control Structures
A computer can process a program in one of the following ways: in sequence; selectively,
by making a choice, which is also called a branch; repetitively, by executing a statement
over and over, using a structure called a loop; or by calling a function.
Program control structures determine how execution of the program should flow. Control
structures provide alternatives to sequential program execution and are used to alter the
sequential flow of execution.
General pseudocode:
BEGIN
statement 1
statement 2
.
.
.
statement N
END
90
General Flowchart
START
Statement 1
Statement 2
• .
• .
•
Statement N
END
Activity 5.1
Write a program that will display your name on the first line, your postal address on
the second line, your email address on the third line, and your telephone number
on the fourth line.
91
5.2 Selection Program Control Structures
Selection program control structures execute statements depending on some condition.
It is organized in such a way that there is a way that there is always a condition or
comparison of two expressions that has to be evaluated first, which will decide the course
of action of the program. Statements (lines of code) are executed selectively, other
statements are skipped. There is a condition to determine which statements to be
executed. Selected statements are executed ONLY once. In C++, the condition will either
evaluate to a Boolean value true or false or integer values 1 (for true) or 0 (for false). If
condition is TRUE one set of statements is executed otherwise the other set is executed.
a) Simple if Statement
Used when there is only one option that should be selected or not. When condition
evaluates to TRUE, statements for the option is executed.
92
The syntax for the if statement is as follows:
if (condition) No semicolon goes here
{
statement 1;
statement 2; Semicolons go here
…
statement n;
}
Example: Write a program that accepts three test scores from the user and the program
should calculate the test scores average. If the average equals 100, the program should
display a message to congratulate the user for earning a perfect average.
#include <iostream>
using namespace std;
int main ()
{
int score1, score2, score3;
double average;
// Get the three test scores
cout << "Enter 3 test scores and I will average them: ";
cin >> score1 >> score2 >> score3;
// Calculate and display the average score
average = (score1 + score2 + score3) / 3.0;
cout << "Your average is " << average << endl;
// If the average equals 100, congratulate the user
if (average = = 100)
{
cout << "Congratulations! perfect average! \n ";
}
return 0;
}
93
The value of (condition) is evaluated first, if it results to a non – zero or true value, then
statement is executed. If(condition) results to a zero or false value, then the program
flow jumps to the next statement after the if structure.
• The condition must always be enclosed with a pair of parentheses, forgetting the
parentheses will result into a syntax error.
• If there is more than one statement to be executed when the condition is non-zero
or true, then these statements must be grouped in a pair of curly brackets.
• Do not place a semi-colon (;) after the (condition) for this will cause a logical error.
Note that Indentation and spacing are for the human reader of a program, not the
computer. Even though the cout statements following the if statement are indented,
the semicolon still terminates the if statement.
General Pseudocode:
BEGIN
IF condition THEN
statement(s)
END IF
END
Activity 5.2a
Write a pseudocode for the program that accepts three test scores from the user
and calculates their average. If the average equals 100, the program should
display a message to congratulate the user for earning a perfect average.
94
General Flowchart
Start
Condition True
?
Statement(s)
Stop
Activity 5.2b
Draw a flowchart for the program that accepts three test scores from the user and
calculates their average. If the average equals 100, the program should display a
message to congratulate the user for earning a perfect average.
95
The syntax for the if-else statement is as follows:
if (condition)
{
statement set 1;
}
else
{
statement set 2;
}
The value of (condition) is evaluated first, if it results to a non-zero or a true value, then
statement set 1 is executed. Otherwise, if is evaluated as zero or false, then the else
part i.e. statement set 2 is executed.
96
General pseudocode:
BEGIN
IF condition THEN
statement(s)
ELSE
statement(s)
END IF
END
Activity 5.2c
Write an if/else statement that assigns 1 to x if y is equal to 100. Otherwise, it
should assign 0 to x.
97
General Flowchart
Start
Condition
False True
?
Statement(s)-1
Statement(s)-2
Stop
Figure 5.3: The if-else Statement Program Control Structures General Flowchart
Activity 5.2d
Draw a flowchart for a program that display PASS if grade scored is 50 or above
otherwise FAIL.
98
The syntax for the if-else if statement is as follows:
if (condition 1)
{
statement set 1;
}
else if (condition 2)
{
statement set 2;
}
.
.
.
else if (condition n)
{
statement set n;
}
else
{
statement set e;
}
General pseudocode:
BEGIN
IF condition1 THEN
statement(s)
ELSEIF condition2 THEN
statement(s)
ELSEIF condition3 THEN
statement(s)
.
.
.
ELSE
statement(s)
END IF
END
99
Example: A program that gets a grade and displays FAIL if grade scored is 0-49, PASS
for 50-59, CREDIT for 60-74, DISTINCTION for 75-100, otherwise INVALID GRADE
ENTERED
BEGIN
GET grd
DISPLAY “FAIL”
DISPLAY “PASS”
DISPLAY “CREDIT”
DISPLAY “DISINCTION”
ELSE
END IF
END
Activity 5.2e
Write a C++ program that gets a grade and displays FAIL if grade scored is 0-49,
PASS for 50-59, CREDIT for 60-74, DISTINCTION for 75-100, otherwise INVALID
GRADE ENTERED
100
General Flowchart
Start
Condition True
Statement(s)
1
True
Condition
Statement(s)
2
...
Statement(s)
Statement(s)
Stop
101
Activity 5.2f
Draw a flowchart for a program that gets a grade and displays FAIL if grade
scored is 0-49, PASS for 50-59, CREDIT for 60-74, DISTINCTION for 75-100,
otherwise INVALID GRADE ENTERED
CASE statement has several values, called case values/ case label or just cases or
options, and only one case value is matched. The value which is used to match against
the cases is called case tag/selector. When a case value matches with the case tag, the
statements under that case value are executed. In C++, the last statement in every case
value is a break statement. Break statement avoids the execution to continue to next
case value.
The syntax for the CASE Statement is as follows:
switch (selector)
{
case label1: statement1;
break;
102
The selector may be an integer or character variable or an expression that evaluates
to an integer or a character. The selector is evaluated and the value compared with
each of the case labels. The case labels must have the same type as the selector
and they must all be different. If a match is found between the selector and one of the
case labels, say label1, then the statements from the statement statement1 until the
next break statement will be executed. If the value of the selector cannot be matched
with any of the case labels, then the statement associated with default is executed.
The default is optional but it should only be left out if it is certain that the selector will
always take the value of one of the case labels. Note that the statement associated with
a case label can be a single statement or a sequence of statements (without being
enclosed in curly brackets).
Example: The following program display out the day of the week depending on the value
of an integer variable day. It assumes that day 1 is Sunday.
#include<iostream>
using namespace std;
int main()
{
int day;
cout<<“Enter number of the day of the week”<<endl;
cin>>day;
switch (day)
{
case 1 : cout << "Sunday";
break;
case 2 : cout << "Monday";
break;
case 3 : cout << "Tuesday";
break;
case 4 : cout << "Wednesday";
103
break;
case 5 : cout << "Thursday";
break;
case 6 : cout << "Friday";
break;
case 7 : cout << "Saturday";
break;
default : cout << "Invalid day number";
break;
}
return 0;
}
A switch statement and an if/else if statement are both useful for implementing
logic that requires branching to different blocks of code.
For example, the following if/else if program is a direct implementation of the logic
from the switch program shown earlier.
#include<iostream>
using namespace std;
int main()
{
int day;
cout<<“Enter number of the day of the week”<<endl;
cin>>day;
if (day == 1)
cout << "Sunday";
else if (day == 2)
cout << "Monday";
else if (day == 3)
cout << "Tuesday";
104
else if (day == 4)
cout << "Wednesday";
else if (day == 5)
cout << "Thursday";
else if (day == 6)
cout << "Friday";
else if (day == 7)
cout << "Saturday";
else
cout << "Not a legal day";
return 0;
}
Example: Write a pseudocode that requests two integers in order to compute one of the
following: the sum, the difference, the product or the quotient depending on
what the user selects from the given menu of arithmetic operations. The choice
is made by entering the option number
105
BEGIN
USE variables: num1, num2, sum, diff, prod, choice As
Integer, quotient As Real
DISPLAY “*****MENU******“
DISPLAY “1 - Addition”
DISPLAY “2 - Subtraction”
DISPLAY “3 – Multiplication”
DISPLAY “4 – Division”
DISPLAY “Enter your choice”
GET choice
DISPLAY “Enter the two integers”
GET num1, num2
CASE (choice)
1:
DISPLAY “Sum is:”, num1+num2
2:
DISPLAY “Difference is:”, num1-num2
3:
DISPLAY “Product is:”, num1*num2
4:
DISPLAY “Quotient is:”, num1/num2
ELSE:
DISPLAY “Invalid choice”
END CASE
END
Activity 5.2g
Write a C++ program that requests two integers in order to compute one of
the following: the sum, the difference, the product or the quotient depending
on what the user selects from the given menu of arithmetic operations. The
choice is made by entering the option number
106
General Flowchart
Start
Condition
?
Stop
Activity 5.2e
Draw a flowchart for a program that requests two integers in order to compute one
of the following: the sum, the difference, the product or the quotient depending on
what the user selects from the given menu of arithmetic operations. The choice is
made by entering the option number.
107
Pre-condition
Pre-condition loop has its condition before the loop body i.e. the condition is tested
(checked) first before executing the loop body.
Post-condition
Post-condition loop has its condition after the loop body i.e. the condition is tested after
executing the loop body. Hence the loop body is executed at least even when the test
fails for the very first check.
Infinite Loops
In all but rare cases, loops must contain within themselves a way to terminate. This means
that something inside the loop must eventually make the test expression false. If a loop
does not have a way of stopping, it is called an infinite loop. Infinite loops keep repeating
until the program is interrupted.
Indefinite loop
Indefinite loop is a loop which you cannot always tell how many times the loop will occur.
108
While … do loop general pseudocode:
BEGIN
WHILE (Condition) DO
Statement(s)
END WHILE
END
Example: A program to display first ten positive integers
BEGIN
USE VARIABLES: num As Integer
num=1
WHILE (num<=10) DO
DIPLAY num, “ ”
COMPUTE num=num+1
END WHILE
END
Start
General Flowchart
Condition True
?
Statement(s)
Stop
109
Activity 5.3a
Draw a flowchart for a program that display first ten positive integers (use while
… do)
While the condition is true the statement is repeatedly executed. The statement may be
a single statement (terminated by a semi-colon) or a compound statement.
110
Do … while loop general pseudocode:
BEGIN
DO
Statement(s)
WHILE (Condition)
END
Statement(s)
Condition True
False
?
Stop
111
Activity 5.3b
Draw a flowchart for a program that display first ten positive integers (use do …
while)
112
Repeat … until loop general pseudocode:
BEGIN
REPEAT
Statement(s)
UNTIL(Condition)
END
Example: A program to display first ten positive integers.
BEGIN
USE VARIABLES: num As Integer
num=1
REPEAT
DIPLAY num, “ ”
COMPUTE num=num+1
UNTIL (num>10)
END
Start
General Flowchart
Statement(s)
True Condition
False
?
Stop
113
Activity 5.3c
Draw a flowchart for a program that display first ten positive integers (use
repeat … until)
counter, startnum and endnum are variables, step determines how to move from
start number to the end number i.e. how many steps at a time. The for loop is specifically
designed to initialize, test, and update a counter variable.
114
Flowchart is the same as for while ... Do loop
Start
Condition True
?
Statement(s)
Stop
The first line of the for loop is the loop header. After the key word for, there are three
expressions inside the parentheses, separated by semicolons.
115
Example: C++ program to display even number between 0 and 100
#include<iostream>
using namespace std;
int main()
{
int num;
for(num=2;num<=100;num = num+2)
{
cout<<num<<“ ”;
}
return 0;
}
1. break Statement
• The break statement is used to terminate a loop immediately, even if the loop
condition is still true. It exits the loop and transfers control to the statement after
the loop.
116
Example:
#include <iostream>
using namespace std;
int main() {
for(int i = 1; i <= 5; i++) {
if(i == 3)
break; // Stops the loop when i is 3
• When i becomes 3, the break statement stops the loop. Values after 3 are not
printed.
2. continue Statement
The continue statement is used to skip the current iteration of the loop and move to
the next iteration. It does not terminate the loop.
Example:
#include <iostream>
using namespace std;
int main() {
for(int i = 1; i <= 5; i++) {
if(i == 3)
continue; // Skips when i is 3
• When i is 3, the continue statement skips printing. The loop continues with the
next value.
117
Nested Loops
• A nested loop is a loop inside another loop. The inner loop executes completely
for each iteration of the outer loop.
• Nested loops are commonly used in:
o Matrices
o Tables
o Patterns
o Multidimensional arrays
int main() {
for(int i = 1; i <= 3; i++) {
for(int j = 1; j <= 3; j++) {
cout << "(" << i << "," << j << ") ";
}
cout << endl;
}
return 0;
}
• The outer loop controls i (rows). The inner loop controls j (columns). For each
value of i, the inner loop runs fully from 1 to 3.
Activity 5.3d
Every for loop can be converted to while loop, but not vice versa. Convert the for
loop program that display even numbers between 0 and 100 into a while…do loop.
118
Unit summary
In this Unit, you have covered the following main points:
• Program control structures determine how execution of the program should flow.
• There are three main types of program control structures: sequential/consecutive
program control structures, selection/alternative program control structures and
iteration/repetition/loop program control structures
• You learnt that in sequential program control structure statements are executed
one after another in the order of their appearance in the source code.
• Selection program control structures execute statements depending on some
condition. There are two main forms of selection program control structures: IF
Statements and CASE/SWITCH Statement
• In iteration program control structures statement(s) are executed several times
depending on the outcome of a condition. Condition for the loop can either be pre-
condition or post-condition.
• You learnt that Iteration program control structures have the following forms:
While … do Loop, Do … while Loop, Repeat … until Loop and For Loop.
You have learnt program control structures and its different forms. In the next unit we will
look at the concept of modular programming where a complex problem is broken down
into smaller solvable problems which are easily managed and maintained.
119
UNIT
6 UNIT 6: FUNCTIONS
Introduction
When solving large problems, it is usually necessary to split the problem down into a
series of sub-problems, which in turn may be split into further sub-problems. This process
continues until problems become of such a size that they can be solved by a single
programmer. The work has to be shared out between a team of programmers, each
programmer ending up with a specification for a part of the system which is to be written
as a function. The problem is ultimately solved by putting these pieces together to form
the complete solution. You will learn in this Unit how and why to modularize programs,
using both functions and procedures. You will also learn scope of variables.
Unit outcomes
By the end of this unit, you must be able to:
• Define ‘modular programming’.
• Explain advantages of modular programming.
• Differentiate a function and a procedure
• Explain types of functions
• Understand function definition, function declaration and function calling.
• Understand overloaded functions, inline functions and recursive functions
• Explain types of variables in a program
• Create and use header files.
Key terms
Ensure that you understand the following key terms or phrases used in this unit: modular
programming, function, function, inbuilt functions, user-defined functions, function
definition, function header, prototype, header file, function call, argument, parameter,
overloaded function, inline function, recursive function and variable scope.
120
6.1 Modular Programming
6.1.1 Modular Programming
A function is a collection of statements that performs a specific task. So far you have used
functions by creating a function called main in every program you’ve written. A program
may be broken up into a set of manageable functions, or modules. This is called modular
programming. A complex problem requires a complex solution. A complex problem
should be broken down into smaller solvable problems. Each smaller problem needs to
be solved independently. The solution to each smaller problem is called a module. A
module can either be a set of functions or procedures.
The modules are then integrated to work together to form the complex solution. This
approach of splitting a complex problem into smaller problems and then solve each
smaller problem on its own and later integrate the solutions is referred to as modular
approach or divide and conquer approach.
121
6.1.2 Function and Procedure
What is a Function?
A function is a piece of program code that performs a specific task when it is called and
it returns a value where it was called.
What is a Procedure?
A procedure is a piece of program code that performs a specific task when it is called and
does not return a value where it was called.
But many times, these two terms (procedure and function) are used interchangeably.
Although that is a case, it is important to note their difference.
Types of functions
There are two types of functions:
a) Pre-defined
b) Programmer-defined
122
Header Files
• A header file contains declarations of functions, variables, and constants.
• To use library functions, we include the header file using the #include
directive.
• Syntax
#include <header_name>
123
Example Program:
#include <iostream>
using namespace std;
int main() {
int num;
cout << "Enter a number: ";
cin >> num; // Input
cout << "You entered: " << num << endl; // Output
return 0;
}
Example Program:
#include <iostream>
#include <cmath>
using namespace std;
int main() {
double num = 25.0;
cout << "Square root of " << num << " is: " << sqrt(num) << endl;
cout << "2 raised to 3 is: " << pow(2, 3) << endl;
return 0;
}
124
o difftime(t1, t2) – Difference between times
o ctime(&time) – Converts time to string
Example Program:
#include <iostream>
#include <ctime>
using namespace std;
int main() {
time_t now = time(0);
cout << "Current time: " << ctime(&now);
return 0;
}
Example Program:
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
int main() {
srand(time(0)); // Seed random generator
cout << "Random number: " << rand() % 100 << endl;
return 0;
}
125
o strcpy(dest, src) – Copy string
o strcmp(str1, str2) – Compare strings
o strcat(dest, src) – Concatenate strings
o strchr(str, ch) – Find character
Example Program:
#include <iostream>
#include <cstring>
using namespace std;
int main() {
char str1[] = "Hello";
char str2[20];
strcpy(str2, str1);
cout << "Copied string: " << str2 << endl;
return 0;
}
Example Program:
#include <iostream>
#include <cctype>
using namespace std;
int main() {
char ch = 'A';
126
if (isupper(ch)) {
cout << ch << " is an uppercase letter." << endl;
}
return 0;
}
Example Program:
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
double num = 123.456789;
return 0;
}
127
Example Program:
#include <iostream>
#include <fstream>
using namespace std;
int main() {
ofstream file("[Link]");
file << "Hello, file!";
[Link]();
Example:
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int arr[] = {5, 2, 9, 1};
sort(arr, arr + 4);
return 0;
}
Activity 6.1
Discuss the differences between header file and a library in C++.
128
6.2 User-defined functions
User-defined functions are also called programmer-defined functions, because they
are defined by the programmer in order to accomplish a specific task.
129
Part enclosed by curly brackets ({}) is called function body.
• It contains statements to be executed to give an outcome when the function is
called.
• It also contains a return statement which returns a value (function outcome) to the
function caller and exits the function.
General Syntax:
type function_name(parameters); //note semi colon (;)
Declaration for the previous function example of adding two numbers is:
int sum (int Num1, int Num2);
Parameter names are optional at declaration. Therefore, above declaration can be
rewritten as:
int sum (int, int);
Function prototype eliminates the need to place a function definition before all calls to the
function. Before the compiler encounters a call to a particular function, it must already
know certain things about the function. In particular, it must know the number of
parameters the function uses, the type of each parameter, and the return type of the
130
function. One way of ensuring that the compiler has this required information is to place
the function definition before all calls to that function. Another method is to declare the
function with a function prototype.
You must either place the function definition or the function prototype ahead of all calls to
the function. Otherwise, the program will not compile.
Activity 6.2a
What role do the parameters of a function play?
131
6.2.2 Calling a Function
A function is executed when it is called. Function main is called automatically when a
program starts, but all other functions must be executed by function call statements.
When a function is called, the program branches to that function and executes the
statements in its body.
The function header is part of the function definition. It declares the function’s return type,
name, and parameter list. It must not be terminated with a semicolon because the
definition of the function’s body follows it.
The function call is a statement that executes the function, so it is terminated with a
semicolon like all other C++ statements. Notice that the function call does not list the
return type and, if the program is not passing data into the function, the parentheses are
left empty.
A function will remain unused until it is called. To call a function, you need to know the
name of the function and parameters data types, if it has any.
A function can be called in a main() or another function. At a function call, the control
of the program is transferred to the function and function executes its statements. When
a function executes a return statement, the control of program is handed back to the caller
(where the call statement is).
132
Argument
An argument, also known as true parameter, is a value that is passed to the function
through function’s parameter.
Parameter
Parameter, also known as formal parameter, is a variable in function header that
receives a value from a function call.
int sum;
int fnum =10; int snum =20;
sum = getSum(fnum, snum); //this calls getSum() function
Passed to a
Passed to b
Same type (int) Type must match
Type must match fnum and snum are
Both int
Both int arguments
133
2. Automatic Memory Allocation
• When a function is called, its local variables are pushed onto the stack.
• When the function ends, its variables are automatically removed (popped).
3. Temporary Storage
Stack memory stores:
• Local variables
• Function parameters
• Return addresses
• Control information about function calls
134
Step-by-Step Execution Flow
Step 1: main() Starts
• main() is executed first.
• A stack frame for main() is created.
135
Example Program Demonstrating Stack Behavior
#include <iostream>
using namespace std;
void func2() {
int c = 30; // Stored on stack
}
void func1() {
int b = 20; // Stored on stack
func2();
}
int main() {
int a = 10; // Stored on stack
func1();
return 0;
}
Stack Overflow
Stack overflow occurs when too many function calls or large local variables exceed
stack size.
Common causes:
• Infinite recursion
• Large arrays declared inside functions
136
Example:
#include<iostream>
using namespace std;
int getSum(int a, int b); //declaration
int main()
{
int sum;
int fnum =10; int snum =20;
sum = getSum(fnum, snum); //function call
cout << fnum << “ + ” << snum << “ = ” << sum;
return 0;
}
int getSum(int a, int b)
{
return a+b;
}
Defining a Procedure
Defining a procedure is the same as defining a function with two differences:
i. It has no return type instead type is replaced with void. Void for no value to return.
ii. It has no return statement. Procedure does not return a value.
137
Example: A display() procedure to display “I am a procedure” can be defined as:
void display() //Has no parameters
{
cout << “I am a procedure”;
}
Declaring a Procedure
Declaring a procedure is the same as declaring a function.
General Syntax:
void procedure_name(parameters); //note semi colon (;)
Calling a Procedure
Calling a procedure is the same as calling a function with the exception; call is not in a
form of assignment statement. Everything remains the same as functions
void displayMessage()
{
cout << "Hello from the function displayMessage.\n";
}
138
Activity 6.2b
Indicate which of the following is the function prototype, the function header, and
the function call:
void showNum(double num)
void showNum(double);
showNum(45.67);
6.2.3 Parameters
A parameter is a special variable that holds a value being passed as an argument into a
function. By using parameters, you can design your own functions that accept data.
Value Parameters
When calling a function with arguments (actual parameters), the value of the argument is
copied from its memory area to another memory area used by the function’s parameter
(formal parameter).
Memory
x=5;
Func1(x);
Function call
copies value of x 5 Function called will use
to another this value
location.
Figure 6.1: Value Parameters
The variable x has the value 5 stored in a memory location. When func1() is called, that
value is copied to another memory location used by the function. If a statement in the
function would change the value to 6, the memory location of the function is affected, but
not the original value of x.
139
Memory
x=5;
Func1(x);
Function has changed
6
the value to 6
Reference Parameters
When arguments have been passed by reference, there is no copying of values. It is
argument’s reference (alias) which is passed to function. Hence, the original argument
and function’s parameter point to the same memory location.
Memory
If func1() changes
5 this value to 6, the
x=5;
value of original
Func1(x); variable x will also
be affected
Function call passes a
reference (alias) of x to
function’s parameter.
140
Defining a function parameter as reference parameter is made by placing an ampersand
sign (&) after the data type.
Function definition:
Example: A program that doubles any integer number that the user enters.
#include <iostream>
using namespace std;
int doubleNum(int &number); // Declaring a function
int main()
{
int num,value;
cout << "Enter a number: ";
cin >> num;
value = doubleNum(num); //function call
cout << "That value doubled is " << value << endl;
return 0;
}
Activity 6.2c
Give an example where an argument should be passed by reference.
141
Default Parameter Value
You can specify a default value for each parameter. Default value is used if that parameter
is left blank when calling to the function.
Example:
int getSum (int a, int b=2)
{
return a+b;
}
Activity 6.2d
What kinds of values may be specified as default arguments?
Example: A program with a function divide() shows the quotient of num1 divided by
num2. If num2 is set to zero, the function returns without performing the division.
#include <iostream>
using namespace std;
void divide (double num1, double num2); // Function prototype
int main()
{
double num1, num2;
cout << "Enter two numbers and I will divide the first\n";
cout << "number by the second number: ";
cin >> num1 >> num2;
142
divide(num1, num2); //function call
return 0;
}
Activity 6.2e
How many return values may a function have?
Example:
#include<iostream>
using namespace std;
int getSum(int, int);
double getSum(double, double);
int getSum(int, int, int);
int main()
{
int a =10; int b= 20; int c =15; int sum1;
143
double d =5.7; double e =10.4; double sum2;
sum1 = getSum(a, b); //two arguments
cout << sum1<< endl;
sum1 = getSum(a, b, c); // three arguments
cout << sum1<< endl;
sum2 = getSum(d, e); // double data type
cout << sum2;
return 0;
}
Activity 6.2f
Is it required that overloaded functions have different return types, different
parameter lists, or both?
144
Include inline directive before a function declaration. Function is compiled as code at the
same point where it is called – no overheads of function calling.
Example:
inline int getSum (int a, int b) // note the word inline here
{
return a+b;
}
1. Iteration
• Iteration is the repetition of execution of a block of code to obtain a solution. It
uses loop control structures such as:
o for loop
o while loop
o do-while loop
Characteristics of Iteration
• Uses loop statements
• Faster execution in many cases
• Does not use function calls repeatedly
• Easier to understand for beginners
145
• The loop starts from 1 to n. Each number is added to total. Finally, the function
returns the sum.
2. Recursion
• Recursion is a programming technique in which a function calls itself repeatedly
to solve a problem. A recursive function solves a problem by breaking it into smaller
subproblems of the same type.
Characteristics of Recursion
• A function calls itself
• Uses selection control structures (if, else, else if)
• Must have a base case to stop recursion
• Each recursive call reduces the problem size
2. Recursive Case
• The part where the function calls itself.
146
6.2.7 Recursive Functions
You have seen instances of functions calling other functions. Function A can call function
B, which can then call Function C. It’s also possible for a function to call itself. A function
that calls itself is a recursive function. Look at this message function:
void message()
{
cout << "This is a recursive function.\n";
message();
}
#include <iostream>
using namespace std;
long factorial (long a);
int main()
{
long num;
cout << "Type a number: ";
cin >> num;
cout << num << "!" <<" = " << factorial (num);
return 0;
}
147
long factorial (long a)
{
if (a > 1)
return (a * factorial (a-1));
else
return (1);
}
Activity 6.2g
What happens if a recursive function does not handle base cases correctly?
File Extension
• Header files are saved with the .h or .hpp extension.
• Examples:
student.h, mathutils.h, main.h
148
Modular Programming in C++
Modular programming means dividing a program into separate files or modules.
Syntax
#include “headerfilename.h”
//note: your header file should not be enclosed in <>
149
Steps to create and use header file
Step 1:
• Generate a file and give it a name with a .h or .hpp extension, such as main.h.
• Place all function declarations within this file.
The #ifndef, #define, and #endif trio prevent multiple inclusions by ensuring that
the contents of the header file are only included once during compilation.
#ifndef MAIN_H
Header Guard
#define MAIN_H
#endif
This is a header file named main.h containing the declaration of an add function that
takes two integers as parameters. If you have more functions or declarations, you can
add them between #ifndef and #endif.
Step 2:
• Generate a new file with the identical name as the one created in step 1, but
conclude it with a .cpp extension, for example, [Link].
• Place all function definitions corresponding to the declarations made in the .h file
(step 1) within this file.
int add(int a, int b)
{ function
return a+b; definition
Step 3:
• In the file where you intend to use the defined functions, #include the header
you created in step 1.
• Include the header file using double quotes instead of angle brackets.
150
#include <iostream>
#include "main.h" Including your header
using namespace std;
int main()
{
cout << add(10, 5) << endl;
return 0;
}
Common Mistakes
• Forgetting to include the header file in .cpp
• Writing function definitions in .h instead of .cpp (unless inline)
• Not using header guards (#ifndef, #define, #endif)
• Using < > instead of " " for user-defined headers
151
6.3.1 Local variables
A local variable is defined inside a function and is not accessible outside the function.
Variables defined inside a function are local to that function. They are hidden from the
statements in other functions, which normally cannot access them. It is created when the
function in which it is declared is called and ceases to exist when the function has finished
execution.
A local variable exists only while the function it is defined in is executing. This is known
as the lifetime of a local variable. When the function begins, its parameter variables and
any local variables it defines are created in memory, and when the function ends, they
are destroyed. This means that any values stored in a function’s parameters or local
variables are lost between calls to the function.
152
Even though there are two variables named num, the program can only “see” one of them
at a time because they are in different functions. When the program is executing in main,
the num variable defined in main is visible. When anotherFunction is called,
however, only variables defined inside it are visible, so the num variable in main is hidden.
In C++, unless you explicitly initialize numeric global variables, they are automatically
initialized to zero. Global character variables are initialized to NULL. Although global
variables can be useful, you should restrict your use of them. Although this approach
might make a program easier to create, it usually causes problems later. The problems
are as follows:
• Global variables make debugging difficult.
• Functions that use global variables are usually dependent on those variables.
• Global variables make a program hard to understand.
In most cases, you should declare variables locally and pass them as arguments to the
functions that need to access them.
You cannot have two local variables with the same name in the same function. This
applies to parameter variables as well. However, you can have a parameter or local
variable with the same name as a global variable or constant. When you do this, the name
of the parameter or local variable shadows the name of the global variable or constant.
This means that the global variable or constant’s name is hidden by the name of the
parameter or local variable.
153
Example: Global variables
#include <iostream>
using namespace std;
void anotherFunction(); // Function prototype
int num = 2; // Global variable
int main()
{
cout << "In main, num is " << num << endl;
anotherFunction(); //function call
cout << "Back in main, num is " << num << endl;
return 0;
}
void anotherFunction()
{
cout << "In anotherFunction, num is " << num << endl;
num = 50;
cout << "But, it is now changed to " << num << endl;
}
Example 1:
#include <iostream>
using namespace std;
int main() {
154
int x = 50; // Local variable
return 0;
}
int getDifference();
int x = 100; // global
int main() {
int result;
result = getDifference();
cout << "Difference between global x and local x: " <<
result << endl;
return 0;
}
int getDifference() {
int x = 50; // local
return ::x - x; // global x - local x
}
155
• Memory
o Stored in data segment (not stack)
• Default Initialization
o Automatically initialized to 0 if not specified
Example:
void countCalls();
int main() {
countCalls();
countCalls();
countCalls();
return 0;
}
void countCalls() {
static int count = 0; // static variable
count++;
cout << "This function has been called " << count << "
times." << endl;
}
156
Activity 6.3
What are the differences between a local variable and a global variable?
Segments of Memory
When a program is loaded into memory, it’s organized into three areas of memory,
called segments:
• Text segment
• Stack segment
• Heap segment
157
6.4.1 Text segment
Sometimes also called the code [Link] is where the compiled code of the program
itself resides. This is the machine language representation of the program steps to be
carried out, including all functions making up the program, both user and system defined.
When a function exits, all of its variables are popped off of the stack (and hence lost
forever). Stack variables are local in nature. There is a limit (varies with Operating
System) on the size of variables that can be store on the stack. This is not the case for
variables allocated on the heap.
The stack grows and shrinks as functions push and pop local variables. There is no need
to manage the memory yourself, variables are allocated and freed automatically. The
stack has size limits. Stack variables only exist while the function that created them, is
running.
158
6.4.3 Heap segment
The heap is a region of your computer's memory that is not managed automatically for
you, and is not as tightly managed by the CPU. It is a more free-floating region of memory
(and is larger). The heap contains a linked list of used and free blocks. New allocations
on the heap (by new or malloc) are satisfied by creating a suitable block from one of the
free blocks. This requires updating list of blocks on the heap.
The size of the heap is set on application startup, but can grow as space is needed (the
allocator requests more memory from the operating system). It is stored in computer RAM
like the stack. Variables on the heap must be destroyed manually and never fall out of
scope. The data is freed with delete, delete[] or free. It is slower to allocate in
comparison to variables on the stack. It is used on demand to allocate a block of data for
use by the program.
You would use the heap if you don’t know exactly how much data you will need at runtime
or if you need to allocate a lot of data. Once you have allocated memory on the heap, you
are responsible for using free() to deallocate that memory once you don't need it any
more. If you fail to do this, your program will have what is known as a memory leak.
Memory Leak occurs when a computer program consumes memory but is unable to
release it back to the operating system. A memory leak can diminish the performance of
the computer by reducing the amount of available memory.
The heap does not have size restrictions on variable size (apart from the obvious physical
limitations of your computer). Heap memory is slightly slower to be read from and written
to, because one has to use pointers to access memory on the heap. Variables created
on the heap are accessible by any function, anywhere in your program. Heap variables
are essentially global in scope.
Activity 6.4
What is the purpose of the new operator?
159
Unit summary
In this Unit, you have covered the following main points:
• Modular programming is when a program is broken up into a set of manageable
functions, or modules.
• A function is a piece of program code that performs a specific task when it is called
and it returns a value where it was called
• A procedure is a piece of program code that performs a specific task when it is
called and does not return a value where it was called.
• There are two types of functions: pre-defined functions and programmer-defined
functions
• A header file is used to define all of the functions, variables and constants
contained in any function library that you might want to use.
• A function definition includes the function’s name, parameters, return type, and
body.
• A function will remain unused until it is called. To call a function, you need to know
the name of the function and parameters data types.
• You learnt that arguments can be passed by value where the value is copied to
another memory location or by reference where there is no copying of values, it is
argument’s reference (alias) which is passed to function.
• You defined scope of an identifier as to where in the program an identifier is
accessible (visible). Variables declared within a function are local to that function
definition. Global variables are defined outside all the functions in a program.
• You learnt that when a program is loaded into memory, it’s organized into three
areas of memory, called segments: text segment, stack segment and heap
segment.
You have learned modular programming using functions and procedures. In the next unit,
we will study arrays for storing and working with multiple values of the same data type.
160
UNIT
7 UNIT 7: ARRAYS
Introduction
In programming I, you worked with simple data types. You learned that C++ data types
fall into three categories; simple data type, structured data type and pointers. This unit
and the next few units focus on structured data types. Data type is called simple if
variables of that type can store only one value at a time. In contrast, in a structured data
type, each data item is a collection of other data items. Simple data types are building
blocks of structured data types. The first structured data type that we will discuss is an
array.
In this unit you will learn how to create and work with single and multidimensional arrays
such as declaring, initializing, assigning values and displaying values. You will also learn
to create tables using two-dimensional arrays, and to analyze the array data by row or by
column. This unit also covers how to pass arrays to functions and advantages and
disadvantages of arrays.
Unit outcomes
By the end of this Unit, you must be able to:
• Define ‘array’
• Explore how to declare and initialize an array
• Discover how to assign values to an array
• Learn how to display values of an array
• Discover how to manipulate data in a two-dimensional array
• Learn how to search an array
• Discover how to pass an array as a parameter to a function
• Discuss advantages and drawbacks of using arrays.
161
Key terms
Ensure that you understand the following key terms or phrases used in this unit: array,
size of array, base address, data type of an array, index, range of index, size declarator,
homogeneous, elements and subscript.
Beyond just storage, a data structure also defines the relationship between the data
elements and the operations that can be performed on that data. For example, a "list"
data structure not only stores elements but also defines operations like "add an element,"
"remove an element," "find an element," or "get the element at a specific position."
The choice of data structure can significantly impact the performance (speed and
memory usage) of an algorithm or a program. A well-chosen data structure can make an
algorithm run much faster, while a poor choice can lead to slow and inefficient code.
162
7.1.2. Primitive Data Structures
Primitive data structures are the most basic and fundamental data types that are
directly provided or built into a programming language. They are the building blocks
upon which more complex data structures are constructed. These types typically
represent single values and are handled directly by the computer's hardware.
Examples of primitive data structures in C++ (and many other languages) include:
• int (integer): Used to store whole numbers (e.g., 5, -100, 0). The range of values
an int can hold depends on the system's architecture (e.g., 16-bit, 32-bit, 64-bit).
o Example: int age = 30;
• char (character): Used to store a single character (e.g., 'A', 'z', '7', '$'). Internally,
characters are often represented by their ASCII (or Unicode) values.
o Example: char initial = 'M';
• bool (boolean): Used to store a logical value, which can only be true or false.
These are fundamental for conditional logic and control flow in programs.
o Example: bool isActive = true;
• void (for no value): While not a data type that holds a value, void is a special
keyword used to indicate the absence of a type. It's commonly used:
o As a function's return type when the function does not return any value
(e.g., void printMessage()).
o As a pointer type that can point to any data type, but cannot be
dereferenced directly without casting (e.g., void* ptr).
These primitive types are directly supported by the CPU and are often stored in
contiguous memory locations, allowing for very fast access and manipulation.
163
7.1.3. Non-Primitive Data Structures
Non-primitive data structures (also known as composite or abstract data types) are
more complex. They are built using primitive data types (or other non-primitive data
structures) and are designed to store and organize collections of data in more
sophisticated ways. They focus on the relationships between multiple data items.
Non-primitive data structures can be broadly categorized into three main types:
1. Linear Data Structures
2. Non-Linear Data Structures
3. Hash-Based Data Structures
164
o Unlike arrays, elements are not necessarily stored in contiguous memory
locations. The links (pointers) define the order.
o Analogy: A treasure hunt where each clue tells you where to find the next
clue.
o Types: Singly linked list (forward links), Doubly linked list (forward and
backward links), Circular linked list (last node points to first).
o Operations: Efficient insertion/deletion anywhere (O(1) if you have a pointer
to the previous node), accessing by index (O(n)).
iii. Stack:
o A linear data structure that follows the Last In First Out (LIFO) principle.
This means the last element added to the stack is the first one to be
removed.
o Operations are typically performed at one end, called the "top" of the stack.
o Analogy: A stack of plates – you always take the top plate, and you always
add new plates to the top.
o Operations: push (add to top), pop (remove from top), peek (view top
element). All are typically O(1).
iv. Queue:
o A linear data structure that follows the First In First Out (FIFO) principle.
This means the first element added to the queue is the first one to be
removed.
o Operations are performed at two ends: elements are added at the "rear" (or
"back") and removed from the "front."
o Analogy: A line of people at a ticket counter – the first person in line is the
first to be served.
o Operations: enqueue (add to rear), dequeue (remove from front), front
(view front element). All are typically O(1).
165
[Link]. Non-Linear Data Structures
In non-linear data structures, data is not stored sequentially. Instead, elements can
be connected in a hierarchical, networked, or other non-sequential manner. This allows
for more complex relationships between data items, making them suitable for modeling
real-world scenarios that are not simple lists.
166
v. Heap:
o A special tree-based data structure that satisfies the heap property.
o In a Max-Heap, for any given node P, the value of P is greater than or equal
to the values of its children. The largest element is always at the root.
o In a Min-Heap, the value of P is less than or equal to the values of its
children. The smallest element is always at the root.
o Heaps are primarily used for implementing priority queues and for the
Heap Sort algorithm.
vi. Graph:
o A non-linear data structure consisting of a set of nodes (or vertices)
connected by a set of edges.
o Graphs are used to represent relationships between discrete objects. They
can model networks (social networks, road networks, computer networks),
dependencies, and flow.
o Types: Directed graphs (edges have a direction), Undirected graphs (edges
have no direction), Weighted graphs (edges have associated values/costs).
o Analogy: A map with cities (nodes) and roads (edges) connecting them.
167
i. Hash Table / Hash Map:
o A data structure that stores key-value pairs.
o Keys are passed through a hash function to compute an index, and the key-
value pair is stored at that index in an underlying array.
o Used for fast lookup, insertion, and deletion.
o Analogy: A dictionary where you can quickly find a word (key) and its
definition (value) by knowing its approximate location (hash index).
o Common Implementations: In C++, std::unordered_map and
std::unordered_set are examples of hash-based containers.
• Algorithm Design: Data structures and algorithms are intrinsically linked. Many
algorithms rely on specific data structures to work efficiently (e.g., Dijkstra's
algorithm for shortest paths uses a priority queue, sorting algorithms often operate
on arrays or lists).
168
• Memory Management: Understanding how data structures store data in memory
helps in writing memory-efficient code and avoiding issues like memory leaks or
excessive memory consumption.
By mastering data structures, you gain the ability to write more efficient, scalable, and
robust software solutions for a wide range of real-world problems.
Activity 7.1
Discuss at least three reasons why understanding data structures is crucial for
any programmer or computer scientist.
7.2. Array
An array allows you to store and work with multiple values of the same data type. The
variables you have worked with so far are designed to hold only one value at a time. For
example, double price; This variable definition, causes only enough memory to be
reserved to hold one value of the specified data type i.e. enough memory for 1 double.
An array works like a variable that can store a group of values, all of the same type. The
values are stored together in consecutive memory locations.
An array in C++ is a variable that refers to a block of memory that can hold multiple values
simultaneously; an array, therefore, represents a collection of values. An array has a
name, and the values it contains are accessed via their position within the block of
memory designated for the array. An array stores a sequence of values, and the values
must all be of the same type. A collection of values all of the same type is said to be
homogeneous.
An array is a method of storing many values of the same data type under the same
variable name. It is a data structure in which data of the same type can be stored and it
provides a way of retrieving each data item (value) in any order. Array values are stored
in contiguous memory addresses in the computer.
169
Memory
1000 1001 1002 1003 1004 1005 ...
addresses
234 18 0 19 45 67 ...
0 1 2 3 4 5 n -1
Array has a name as it is the case with any ordinary variable. Each data item (single
value) of an array is called an element. Index is a value that shows/represents a position
of an element in the array. Total number of elements an array can hold is called size or
array size. By default, index value starts from 0 and ends at (size -1). Usually, index is
an integer value. The amount of memory used by an array depends on the array’s data
type and the number of elements.
ii. access(array, index) value: This function takes an array and index
as input and accesses the data element of that position. When the array is newly
created, this operation must indicate an error because initially each array is by
default empty.
Activity 7.2a
What is “array bounds checking”? Does C++ perform it?
170
1.2.2. Declaring and Initializing an Array
The general syntax for array declaration is:
type array_name[size];
Examples:
int grades[5];//array that holds five grades of data type integer
double salaries[10]; /* array that holds salaries for the 10
employees of data type double */
Figure 7.2: hours array - enough memory to hold six int value
The name of this array is hours. The number inside the brackets is the array’s size
declarator. It indicates the number of elements, or values, the array can hold. The hours
array can store six elements, each one an integer. An array’s size declarator must be a
constant integer expression with a value greater than zero. It can be either a literal, as in
int hours[6];, or a named constant, as shown below:
const int SIZE = 6;
int hours[SIZE];
The amount of memory used by an array depends on the array’s data type and the
number of elements. The age array, defined below, is an array that holds six short int
values.
short age[6];
On a typical PC, a short int uses 2 bytes of memory, so the age array would occupy
12 bytes. The size of an array can be calculated by multiplying the number of bytes
needed to store an individual element by the number of elements in the array.
171
You may initialize an array at declaration:
int grades[5] = {40, 52, 67, 33, 84}; /* index 0 has 40,
index 1 has 52,index 2 has 67,index 3 has 33,index 4 has 84.*/
During Initializing the size, in this case (5) is optional. You may write it as:
int grades[] = {40, 52, 67, 33, 84};
Array allows us to assign values using a loop. It also allows us to display its values using
a loop. Imagine you write a program that will get 20 numbers from a user you would have
the following statements written 20 times:
172
cout << “Enter a number :”;
cin >> number1; /* remaining 19 statements would have number2,
number3 up to number20 */
Even though most C++ compilers require the size declarator of an array definition to be
a constant or a literal, subscript numbers can be stored in variables. This makes it
possible to use a loop to “cycle through” an entire array, performing the same operation
on each element. With array, you can use the following code to get 20 numbers from the
user.
int numbers[20];
for(int i=0;i<20;i++)
{
cout << “Enter a number => ”;
cin >> numbers[i];
}
A programmer has been saved from writing more lines of code. But for the user it is still
tedious because the user has to enter 20 numbers during a single program execution. In
most cases the program input does not come from the user. The data might be
somewhere in a database or file. So, the program retrieves the data e.g. grades, from the
file (database) and assign it to the array in a loop.
Example:
int grades[5] = {40, 52, 67, 33, 84};
cout << grades[0]; // displays 40 (element at index=0)
cout << grade[3]; // displays 33 (element at index=3)
You can also use a loop to display all values in an array as shown below:
for(int i=0; i<5;i++)
{
cout << grades[i] <<endl;
}
173
Activity 7.1b
What is the difference between an array’s size declarator and a subscript?
The arrays that you have studied so far are called one-dimensional arrays because they
can only hold one set of data. Two-dimensional arrays, which are also called 2D arrays,
can hold multiple sets of data. It’s best to think of a two-dimensional array as a table
having rows and columns of elements, figure 1.2 shows an array of grade scores that has
three rows and five columns.
1 2 3 4 5 Grades
1 50 45 70 65 49
Students
2 55 87 41 65 34
3 64 53 81 57 48
General syntax:
type array_name[m][n]; // n x m array (m x n matrix)
//Notice that each number is enclosed in its own set of brackets.
174
Example:
int studentGrades[3][5]; //3 students(rows) and 5 grades(columns)
As with one-dimensional arrays, two-dimensional arrays can be initialized when they are
created. When initializing a two-dimensional array, it helps to enclose each row’s
initialization list in a set of braces.
Example:
int studentGrades[3][5] = {
{45, 40, 52, 67, 33},
{48, 75, 57, 64, 88},
{53, 46, 38, 78, 66},
};
175
Assigning five grades of a first student will be:
int grades[3][5]; //first declare the array
grades[0][0] = 45;
grades[0][1] = 40;
grades[0][2] = 52;
grades[0][3] = 67;
grades[0][4] = 33;
You can also use a nested loop to display all values in a 2D array as shown below:
for(int i=0; i<3;i++)
{
for(int j=0;j<5;j++)
{
cout << grades[i][j] << “\t”;
}
cout << endl;
}
176
7.3.4. Arrays with Three or More Dimensions
C++ permits arrays to have multiple dimensions. C++ allows you to create arrays with
virtually any number of dimensions. Here is an example of a three-dimensional (3D) array
definition:
double seat[3][5][8];
This array can be thought of as three sets of five rows, with each row containing eight
elements. The array might be used, for example, to store the price of seats in an
auditorium that has three sections of seats, with five rows of eight seats in each section.
Arrays with more than three dimensions are difficult to visualize but can be useful in some
programming problems.
Activity 7.3
A DVD rental store keeps DVDs on 50 racks with 10 shelves each. Each shelf
holds 25 DVDs. Define a 3D array to represent this storage system.
Example:
int GradeA[6] = {10, 20, 30, 40, 50, 60};
int GradeB[6] = {20, 40, 60, 80, 10, 12};
for (int i = 0; i< 6; i++)
{
GradeA[i] = GradeB[i];
}
177
On the first iteration of the loop, i = 0, so GradeA[0] is assigned the value stored in
GradeB[0]. On the second iteration, i = 1, so GradeA[1] is assigned the value
stored in GradeB[1]. This continues until, one by one, all the elements of GradeB are
copied to GradeA. When the loop is finished executing, both arrays will contain the
values 20, 40, 60, 80, 10, 12.
Example:
for(int i=0; i<3;i++)
{
for(int j=0;j<5;j++)
{
total += grades[i][j];
}
}
// Display the sum
cout << "The total is " << total << endl;
178
First, we copy the value in the first array element to the variable named highest. Then
the loop compares all of the remaining array elements, beginning at subscript 1, to the
value in highest. Each time it finds a value in the array that is greater than highest, it
copies that value to highest. When the loop has finished, highest will contain the highest
value in the array.
The following code finds the lowest value in the array:
int count;
int lowest;
lowest = numbers[0];
for (count = 1; count < SIZE; count++)
{
if (numbers[count] < lowest)
lowest = numbers[count];
}
179
for(i = Size - 1; i >= Location - 1; i--)
{
A[i + 1] = A[i];//shifting element to right by 1 position
}
A[Location - 1] = Element;
Size = Size + 1;
}
180
The entire array is passed by reference; individual array elements are passed by value
exactly as simple variables are. To pass an element of an array to a function, use the
subscripted name of the array element as an argument in the function call.
Example:
#include <iostream>
using namespace std;
int main()
{
int marks[5]={88,76,90,62,69};
display(marks); //function call
return 0;
}
181
• In an array, insertion and deletion of elements in-between positions require data
movement.
• An array provides static allocation, which means the space allocation done once
during the compile time cannot be changed during run-time.
182
7.4.4. Applications of Arrays
The following list indicates where arrays are most beneficial:
• Arrays form the basis for several more complex data structures such as heaps and
hash tables and can be used to represent strings, stacks, and queues.
• Arrays can be used to store two-dimensional data when represented as matrix and
matrix operations.
• They can also be used for indexing, searching, and sorting keys.
Activity 7.4
When you pass an array name as an argument to a function, what is actually being
passed?
Unit summary
In this Unit, you have covered the following main points:
• The definition of an array as a method of storing many values of the same data
type under the same variable name
• The three basic operations of an array are creating the array, access the values in
the array and store the values in the array.
• Two-dimensional array is like several identical arrays put together. It is useful for
storing multiple sets of data.
• To pass an array as an argument to a function, simply pass the name of the array,
the entire array is passed by reference.
• Arrays are well known in applications such as searching, hash tables, matrix
operations, and sorting.
• Arrays are useful to implement other data structures like linked lists, stacks,
queues, trees etc.
• Arrays provide static memory management. Hence, during execution, the size can
neither be grown nor shrunk.
You have learnt arrays and its operations. In the next unit we will look at how elements
are searched and sorted in an array.
183
UNIT
UNIT
8 8: SEARCHING AND SORTING ARRAY ELEMENTS
Introduction
It’s very common for programs not only to store and process data stored in arrays, but to
search arrays for specific items as we as sorting the items. One of the most time-
consuming tasks in computing is the retrieval of target information from huge data, which
needs searching. Searching is the process of finding the location of the target among a
list of objects. There are certain ways of organizing data, which make the search process
more efficient. If the data is kept in a proper order, it is much easier to search. Sorting is
a process of organizing data in a certain order to help retrieve it more efficiently. This unit
you will learn searching and sorting methods. You will analyse the algorithms in terms of
time complexity as well advantages and disadvantages of each algorithm.
Unit outcomes
By the end of this unit, you must be able to:
• Define ‘searching’ and ‘sorting’
• Learn how to implement the linear search and binary search algorithms
• Differentiate internal sorting from external sorting
• Explore how to sort an array using the bubble sort, selection sort, and insertion
sort algorithms
Key terms
Ensure that you understand the following key terms or phrases used in this unit:
searching, sorting, sequential search, binary search, internal sorting, external sorting,
bubble sort, selection sort, insertion sort, passes, sort stability, sort order and sort
efficiency.
184
8.1. Searching and Sorting
8.1.1. Searching
Searching is the process of locating target data. Searching is the process of finding the
location of the target among a list of objects. A searching algorithm accepts two
arguments as parameters: - a target value to be searched and the list to be searched.
The search algorithm searches a target value in the list until the target key is found or can
conclude that it is not found.
One of the most popular applications of search algorithms is adding a record in the
collection of records. While adding, the record is searched by key and if not present, it is
inserted in the collection. Such a technique of searching the record and inserting it if not
found is known as search and insert algorithm.
Search techniques may vary according to data organization. The data may be stored on
a secondary storage or permanent storage area. If the search is applied on the table that
resides at the secondary storage (hard disk), it is called as external searching, whereas
searching of a table that is in primary storage (main memory) is called as internal
searching which is faster than external searching.
185
8.1.2. Sorting
Sorting is the operation of arranging the records of a table according to the key value of
each record, or it can be defined as the process of converting an unordered set of
elements to an ordered set of elements. Sorting is a process of organizing data in a certain
order to help retrieve it more efficiently.
Internal Sorting
Any sort algorithm that uses main memory exclusively during the sorting is called as an
internal sort algorithm. This assumes high-speed and random access to all data
members. Internal sorting is faster than external sorting. The various internal sorting
techniques are the following: Bubble sort, Selection sort, Insertion sort, Quick sort, Shell
sort, Heap sort, Radix sort and Bucket sort.
External Sorting
Any sort algorithm that uses external memory, such as tape or disk, during the sorting is
called as an external sort algorithm. Merge sort uses external memory. Other algorithms
may read the initial values from a magnetic tape or write sorted values to a disk, but this
is not using external memory during the sort.
186
8.1.3. General Sort Concepts
The following are some general terms related to sorting.
1. Sort Order: - Data can be ordered either in ascending or in descending order. The
order in which the data is organized, either ascending or descending, is called sort
order.
2. Sort Stability: - A sorting method is said to be stable if at the end of the method,
identical elements occur in the same relative order as in the original unsorted set.
While sorting, we must take care of the special case — when two or more of the
records have the same key, it is important to preserve the order of records in this
case of duplicate keys.
4. Passes: - During the sorted process, the data is traversed many times. Each
traversal of the data is referred to as a sort pass. Depending on the algorithm, the
sort pass may traverse the whole list or just a section of the list. In addition, the
characteristic of a sort pass is the placement of one or more elements in a sorted
list.
Activity 8.1
State whether the following statement is True or False
Any sort can be modified to sort in either ascending or
descending order.
187
8.2. Searching Algorithms
A search algorithm is a method of locating a specific item in a collection of data. The
two basic search techniques are the following:
• Sequential search
• Binary search
It uses a loop to sequentially step through an array, starting with the first element. It
compares each element with the value being searched for, and stops when either the
value is found or the end of the array is encountered. If the value being searched for is
not in the array, the algorithm will search to the end of the array.
The number of comparisons depends on where the target data is stored in the search list.
If the target data is placed at the first location, we get it in just one comparison. Two
comparisons are needed if the target data is in the second location. Similarly, i
comparisons are required if the target data is at the ith location and n comparisons, if it
is at the nth location.
Algorithm:
Step 1: Set-up a flag to indicate “element not found”
Step 2: Take the first element in the list
Step 3: If the element in the list is equal to the desired element
• Set flag to “element found”
• Display the message “element found in the list”
• Go to step 6
Step 4: If it is not the end of list,
• Take the next element in the list
188
• Go to step 3
Step 5: If the flag is “element not found”
• Display the message “element not found”
Step 6: End of the Algorithm
The function LinSearch() returns the location of the element if found or returns -1
if the element is not found.
189
[Link]. Disadvantages of Sequential Search
The following are some of the disadvantages of linear search:
1. This method is insufficient when large number of elements is present in list.
2. It consumes more time and reduces the retrieval rate of the system.
3. In the case of ordered data other search techniques such as binary search is
found more suitable.
190
Example 2: Linear search with a function
#include <iostream>
using namespace std;
void linear_search(int[], int);
int size;
int main()
{
int i, element;
cout<<"Enter the size of the array: ";
cin>>size;
int arr_search[size];
cout << "\nEnter"<<size <<"Elements for Searching:"<<endl;
linear_search(arr_search, element);
}
191
8.2.2. Binary Search
The binary search is a clever algorithm that is much more efficient than the linear search.
Its only requirement is that the values in the array be in order. The algorithm starts
searching with the middle element. The binary search is based on the approach divide-
and-conquer.
Binary search algorithm starts with the element in the middle. If that element happens to
contain the desired value, then the search is over. Otherwise, the value in the middle
element is either greater than or less than the value being searched for.
If it is greater than the desired value then the value (if it is in the list) will be found
somewhere in the first half of the array. If it is less than the desired value then the value
(again, if it is in the list) will be found somewhere in the last half of the array. In either
case, half of the array’s elements have been eliminated from further searching.
If the item is less than the middle element, it starts over searching the first half of the list.
If the item is greater than the middle element, the search starts over starting with the
middle element in the second half of the list. It then continues halving the list until the item
is found.
To implement binary search method, the elements must be in sorted order. Search is
performed as follows:
• The key is compared with item in the middle position of an array
• If the key matches with item, return it and stop
• If the key is less than mid positioned item, then the item to be found must
be in first half of array, otherwise it must be in second half of array.
• Repeat the procedure for lower (or upper half) of array until the element
is found.
192
int BinSearch(int list[], int item)
{
int left = 0;
int right = n-1;
int mid;
while(left <= right)
{
mid = (left + right)/2;
if(item > list[mid])
{
left = mid+1;
}
else if(item < list[mid])
{
right = mid - 1;
}
else
{
item = list [mid];
index = mid;
return true;
}
}// while
return false;
}
193
Example 1: Binary search without using a function.
#include<iostream>
using namespace std;
int main()
{
int n, i, arr[n], search, first, last, middle;
cout<<"Enter total number of elements: ";
cin>>n;
cout<<"Enter "<<n<<" numbers\n";
first = 0;
last = n-1;
middle = (first + last)/2;
194
Example 2: Binary search with a function
#include <iostream>
using namespace std;
void binary_search(int[], int);
int size;
int main()
{
int arr_search[size], i, element;
cout<<"Enter the size of the array: ";
cin>>size;
cout <<"\nEnter"<< size <<"Elements for Searching:"<<endl;
195
Activity 8.2
If a linear search is performed on an array, and it is known that some items are searched
for more frequently than others, how can the contents of the array be reordered to
improve the average performance of the search?
Example: Given the following unsorted list of elements, sort it using selection sort
5 7 2 8 9 1
What will be results of selection sort for each pass?
196
Table 8.1: Selection Sort
Unsorted 5 7 2 8 9 1
Pass 1 1 7 2 8 9 5
Pass 2 1 2 7 8 9 5
Pass 3 1 2 5 8 9 7
Pass 4 1 2 5 7 9 8
Pass 5 1 2 5 7 8 9
Sorted 1 2 5 7 8 9
197
Example: C++ Program that uses selection sort algorithm to sort elements
#include <iostream>
using namespace std;
void SelectionSort (int arr[], int n);
int main()
{
int n, i;
cout<<"\nEnter the number of data element to be sorted:";
cin>>n;
int arr[n];
for(i = 0; i < n; i++)
{
cout<<"Enter element "<<i+1<<": ";
cin>>arr[i];
}
SelectionSort(arr, n);
// Display the sorted data.
cout<<"\nSorted Data ";
for (i = 0; i < n; i++)
cout<<":"<<arr[i];
return 0;
}
198
8.3.2. Bubble Sort
The bubble sort is an easy way to arrange data in ascending or descending order. The
bubble sort works by comparing each item in the list with the item next to it and swapping
them if required. The algorithm repeats this process until it makes a pass all the way
through the list without swapping any items (in other words, all items are in the correct
order). This causes larger values to ‘bubble’ to the end of the list while smaller values
‘sink’ towards the beginning of the list. In brief, the bubble sort derives its name from the
fact that the smallest data item bubbles up to the top of the sorted array.
Example: Given the following unsorted list of elements, sort it using bubble sort
76 67 36 55 23 14 6
199
Step 4 36 23 14 6 55 67 76
Pass 4 Step 1 23 36 14 6 55 67 76
Step 2 23 14 36 6 55 67 76
Step 3 23 14 6 36 55 67 76
Pass 5 Step 1 14 23 6 36 55 67 76
Step 2 14 6 23 36 55 67 76
Pass 6 Step 1 6 14 23 36 55 67 76
Sorted 6 14 23 36 55 67 76
Step 3: stop
void bubblesort(int A[max], int n)
{
int i, j,temp;
for(i = 1; i < n; i++) // number of passes
{
for(j = 0; j < n − i; j++) // j varies from 0 to n − i
{
if( A[j] > A[j + 1] ) // compare two successive numbers
{
temp = A[j]; // swap A[j] with A[j + 1]
A[j] = A[j + 1];
A[j + 1] = temp;
}
}
}
200
Example: C++ Program that uses bubble sort algorithm to sort elements
#include <iostream>
using namespace std;
void BubbleSort (int arr[], int n);
int main()
{
int n, i;
cout<<"\nEnter the number of data element to be sorted: ";
cin>>n;
int arr[n];
for(i = 0; i < n; i++)
{
cout<<"Enter element "<<i+1<<": ";
cin>>arr[i];
}
BubbleSort(arr, n);
// Display the sorted data.
cout<<"\nSorted Data ";
for (i = 0; i < n; i++)
cout<<"->"<<arr[i];
return 0;
}
201
8.3.3. Insertion Sort
Both the selection and bubble sorts exchange elements. But insertion sort does not
exchange elements. The insertion sort works just like its name suggests — it inserts each
item into its proper place in the final list. In insertion sort the element is inserted at an
appropriate place similar to card insertion.
The simplest implementation of this requires two list structures: the source list and the list
into which the sorted items are inserted. The list is divided into two parts sorted and
unsorted sub-lists. In each pass, the first element of unsorted sub list is picked up and
moved into the sorted sub list by inserting it in suitable position.
The selection sort algorithms construct the sorted sequence, one element at a time, by
adding elements to the sorted sequence in order. At each step, the next element to be
added to the sorted sequence is selected from the remaining elements.
Example: Given the following unsorted list of elements, sort it using insertion sort
78 23 45 8 32 36
What will be results of insertion sort for each pass?
202
Insertion Sort Algorithm:
void InsertionSort(int A[], int n)
{
int i, j, element;
for(i = 1; i < n; i++)
{
element = A[i]; // insert ith element in 0 to i − 1 array
j = i;
while((j>0)&&(A[j−1]> element))//compare if A[j−1]> element
{
A[j] = A[j − 1]; // shift elements
j = j − 1;
}
A[j] = element; // place element at jth position
}
}
Example: C++ Program that uses insertion sort algorithm to sort elements
#include <iostream>
using namespace std;
void insertion(int[]);
int size;
int main()
{
int arr_sort[size], i;
cout << "Enter number of elements to Sort : ";
cin>>size;
for (i = 0; i < size; i++)
{
cin >> arr_sort[i];
}
cout << "\nYour Data :";
for (i = 0; i < size; i++) {
cout << "\t" << arr_sort[i];
}
insertion(arr_sort);
}
203
{
fn_arr[j + 1] = fn_arr[j];
j = j - 1;
}
fn_arr[j + 1] = t;
}
cout << "\n\nSorted Data :";
for (i = 0; i < size; i++)
{
cout << "\t" << fn_arr[i];
}
}
Activity 8.3
Why is selection sort more efficient than bubble sort on large arrays?
Unit summary
In this Unit, you have covered the following main points:
• The definition of searching as the process of finding the location of the target
among a list of objects.
• The definition of sorting as a process of organizing data in a certain order to help
retrieve it more efficiently.
• A search algorithm is a method of locating a specific item in a collection of data,
basic search techniques are sequential search and binary search.
• A sequential search begins with the first available record and proceeds to the next
available while binary search algorithm starts with the element in the middle, binary
requires values in the array to be in order unlike sequential
• The performance of a searching algorithm can be computed by counting the
number of comparisons to find a given value.
• A sorting algorithm is a technique for scanning through an array and rearranging
its contents in some specific order.
• Sorting algorithms are divided into Internal sorting and external sorting
204
• Internal sorting uses main memory exclusively during the sorting, examples
include bubble sort, selection sort and insertion sort. External sorting uses external
memory during sorting, example is merge sort.
• The selection sort algorithms construct the sorted sequence, one element at a
time, by adding elements to the sorted sequence in order.
• The bubble sort works by comparing each item in the list with the item next to it
and swapping them if required.
• The insertion sort inserts each item into its proper place in the final list.
You have learnt different searching algorithms for location target item in the list of items
and also sorting algorithms for scanning through a list of items and rearranging them into
a specific order. In the next unit we will look at manipulating variable whose value is the
address of another variable. We will also look at how we can dynamically allocate memory
to a program while its running.
205
UNIT
9 UNIT 9: POINTERS
Introduction
Every variable in an executing program is allocated a section of memory large enough to
hold a value of that variable’s type. Current C++ compilers that run on PCs usually
allocate a single byte to variables of type char, two bytes to variables of type short, four
bytes to variables of type float and long, and 8 bytes to variables of type double. Each
byte of memory has a unique address. A variable’s address is the address of the first byte
allocated to that variable.
Each byte in a computer’s memory is numbered with a unique address. The first address
is 0, and the locations are numbered sequentially up to some maximum value allowed by
the operating system and hardware. A C++ variable is stored in memory, so each variable
is stored at a particular address. In Previous units, you learned that C++’s data types are
classified into three categories: simple, structured, and pointers. Until now, you have
studied only the first two data types. This chapter discusses the third data type called the
pointer data type. You will first learn how to declare pointer variables and manipulate the
data to which they point. Later, you will use these concepts when you study dynamic
memory allocation.
Unit outcomes
By the end of this unit, you must be able to:
• Define ‘Pointer’
• Differentiate reference and dereference operators
• Explore how to declare and manipulate pointer variables
• Understand pointer arithmetic
• Examine the relationship between arrays and pointers
• Understand how to use pointers as parameters of a function
• Explore how to use the new and delete operators to manipulate dynamic
variables
206
Key terms
Ensure that you understand the following key terms or phrases used in this unit: pointer,
reference operator, dereference operator, pointer arithmetic, pointer of pointer, dynamic
memory allocation, memory leak, dangling pointer, null pointers and void pointers.
9.1. Pointer
You have worked with variables for quite some time, before using a variable, you must
declare it. During variable declaration, the program creates a memory space that the
variable would use to store its value. You know that a variable has a name (an identifier)
and can contain a value. Now where exactly in the memory is this variable created?
Every variable is assigned a memory location whose address can be retrieved using the
address operator &. The address of a memory location is called a pointer. Every variable
in an executing program is allocated a section of memory large enough to hold a value of
that variable’s type. When you declare a variable, the amount of memory needed is
assigned for it at a specific location in memory. Each variable declared has its unique
memory address. For example:
This declares a variable with identifier num of type Integer and is assigned a value of
25. What we don’t know is the memory address of num (where exactly in memory is num
located). To know the memory address of num we just precede it with &
cout << #
This may display something like: 0xbfebd5c0. So, we say variable num has address of
0xbfebd5c0 in primary memory.
207
9.1.1. Stack and Heap Memory
In C++ application, memory is divided into two: stack and heap. All variables declared
inside the current function will take up memory in the top stack frame. If the current
function calls another function, a new frame is added on the stack. So, the second
function has its own stack frame to work with, different and isolated from the first function’s
frame. Stack frames provide an isolated memory workspace for each function. If a
variable is declared inside one function’s stack frame, calling another function won’t
change it unless you specifically tell it to. Also, when the function is done running, its
stack frame goes away, and all of the variables declared within the function no longer
take up memory. Variables that are stack-allocated do not need to be deallocated
(deleted) by the programmer; it happens automatically.
The heap is an area of memory that is completely independent of the current function or
stack frame. Variables on the heap may still exist even when the function in which they
were created has completed Variables on the heap must be deallocated (deleted) by a
programmer. That is, deallocation does not happen automatically, unless you use smart
pointers. Variables on a heap memory are allocated dynamically using a new operator
and deallocated using delete operator. Pointers are used to access variables declared
in the heap memory. Our first part of discussion on pointers will use variables declared
on the stack and later we will discuss dynamic allocation.
208
The values contained in each variable after the execution of this, are shown in the figure
9.1. assume that address of Mphatso is 1776.
Mphatso
25 (Memory)
1775 1776 1777
&
Mercy John
25 1776
If we write:
Chisomo = *John;
(that we could read as: "Chisomo equal to value pointed by John") Chisomo would take
the value 25, since John is 1776, and the value pointed by 1776 is 25.
John
1776
25
Chisomo
Figure 9.2: Pointer Operators
Reference operator: & is the reference operator and can be read as “address of” or “the
address to”. In C++, the ampersand, &, also called the address of operator, is a unary
operator that returns the address of its operand.
209
Dereference operator: * is the dereference operator and can be read as “value pointed
by” or “the content of”. Every unit until now you have used the asterisk character, *, as
the binary multiplication operator. C++ also uses * as a unary operator. When used as a
unary operator, *, commonly referred to as the dereferencing operator or indirection
operator, refers to the object to which its operand (that is, the pointer) points. Dereference
operator is also called indirection operator which stems from the fact that the data is
accessed “indirectly.”
Example:
int *pNum;
double* pPrice;
char *pName;
Note that * (asterisk) indicates that the variable is a pointer. The data type of a pointer
should match that of variable referenced to.
210
You can also assign a value to a pointer during declaration.
int* pNum = #
Example:
#include <iostream>
using namespace std;
int main()
{
int x = 25; // int variable
int *ptr; // Pointer variable, can point to an int
ptr = &x; // Store the address of x in ptr
cout << "The value in x is " << x << endl;
cout << "The address of x is " << ptr << endl;
return 0;
}
Activity 9.1
Write a C++ statement to declare a variable named dblPtr as a pointer to double
and assign it the address of double variable DblVal.
.
211
9.2. Arrays and Pointers
9.2.1. Arrays and Pointers Concept
Array names can be used as pointer constants, and pointers can be used as array names.
You learned earlier that an array name, without brackets and a subscript, actually
represents the starting address of the array. This means that an array name is really a
pointer.
#include <iostream>
using namespace std;
int main()
{
short numbers[] = {10, 20, 30, 40, 50};
cout << "The first element of the array is ";
cout << *numbers << endl;
return 0;
}
This print: The first element of the array is 10. Because numbers works
like a pointer to the starting address of the array, the first element is retrieved when
numbers is dereferenced. So, how could the entire contents of an array be retrieved
using the indirection operator? Remember, array elements are stored together in
memory.
The concept of array is very much bound to the one of the pointers. In fact, the identifier
of an array is equivalent to the address of its first element, as a pointer is equivalent to
the address of the first element that it points to, so in fact they are the same concept. If
we know address for the first item in an array, then the address for the 2nd item will be
found by incrementing the address by 1. 3rd item by incrementing address by 2 etc. This
is so because the items of arrays are stored contiguously in the memory.
212
Echoing array name gives address of the first item. To have address of the second item,
then add 1 to the array name.
cout << array_name; //1st item address
cout << (array_name +1); //2nd item address
To access the value of array at index 1 (2nd item) using pointer notation, then just do:
cout << *(array_name+1);
Example:
#include <iostream>
using namespace std;
int main()
{
int numbers[] = {10, 20, 30, 40, 50};
cout << "The first element of the array is ";
cout << *numbers << endl;
cout << "The second element of the array is ";
cout << *(numbers +1) << endl;
cout << "The third element of the array is ";
cout << *(numbers +2) << endl;
cout << "The fourth element of the array is ";
cout << *(numbers +3) << endl;
cout << "The last element of the array is ";
cout << *(numbers +4) << endl;
return 0;
}
The parentheses are critical when adding values to pointers. The * operator has
precedence over the + operator, so the expression *numbers + 1 is not equivalent to
*(numbers + 1). The expression *numbers + 1 adds one to the contents of the first
element of the array, while *(numbers + 1) adds one to the address in numbers, then
dereferences it.
Array are said to be constant pointers hence you cannot assign it to anything like:
array_name = some_value; // this is wrong
213
Note that you can assign an array to a pointer i.e.
pointer_name = array_name;
Activity 9.2a
Rewrite the following loop so it uses pointer notation (with the indirection operator)
instead of subscript notation.
for (int x = 0; x < 100; x++)
cout << array[x] << endl;
Example:
Let’s make the following assumptions:
• integer variable occupies a memory of 4 bytes
• double variable occupies a memory of 16 bytes
Suppose also that:
• integer variable iNum has a value of 20 at memory address of 1000
• double variable dNum has a value of 1.75 at memory address of 2000
• pointer pINum reference to iNum (int* pINum = &iNum)
• pointer pDNum references to dNum (double* pDNum = &dNum)
214
Addresses 998 999 1000 1001 1002 1003 1004 1005
20 15
Values
iNum pINum
Values pDNum
dNum
Since pINum stored address of 1000, you may think that after the above statement the
value of pINum is 1001. It isn’t, the result is actually 1004. This is so because the integer
is said to occupy a memory of 4 bytes hence pINum++ will increase pINum by 4 bytes.
Since 1004 has a value of 15. then *(pINum++) will be 15, pINum + 2 will result into
1008 (2 four bytes added).
Similarly, the result of pDNum++ will be 2016. pDNum is of type double. Double is
assumed to occupy a memory of 16 bytes, hence adding 1 will be actually adding 16
bytes.
Activity 9.2b
Assume ptr is a pointer to an int and holds the address 12000. On a system with
4-byte integers, what address will be in ptr after the following statement?
ptr += 10;
215
9.2.3. Pointer of Pointer
A pointer may point to another pointer i.e. it may have an address of another pointer. We
can have a chain of pointers where pointer A points to pointer B which also points to
pointer C which finally points to ordinary variable D. A pointer may point to another pointer
i.e. it may have an address of another pointer. See illustration below:
Addresses
1000
20
Values
Num
Addresses 4000
1000
Values
pNum
Addresses 6000
4000
Values
ppNum
We can have a chain of pointers where pointer A points to pointer B which also points to
pointer C which finally points to ordinary variable D, etc. So far, we have used one asterisk
(*) in declaring and dereferencing pointers since we have been working with 1st level
216
pointers. To declare and dereference 2nd level pointer we use two asterisks (**). The 3rd
level pointer we use three asterisks (***) and so on.
From illustration:
int num =20;
int* pNum = # //a pointer of num
int** ppNum = &pNum;/*a pointer of a pointer pNum note the use
of two asterisks */
Hence:
cout << pNum; //will display 1000
cout << *pNum; //will display 20
cout << ppNum; // will display 4000
cout << **ppNum; /* will display 20. Note use of two asterisks
in this dereferencing */
Activity 9.2c
Write a statement that displays the address of the variable gender.
A pointer can be used as a function parameter. It gives the function access to the original
argument, much like a reference parameter does. This is how you declare a pointer
parameter.
void doubleValue(int *val);
217
This is how it can be called:
doubleValue(&number);
If you don’t want a value to be modified in the function, then use the key word const in
front of the parameter in the function header.
void find(const char* str)
218
You can also return a pointer from a function. To do so, you would have to declare a
function returning a pointer as in the following example:
int * myFunction()
{
// statements
}
Activity 9.3
Under what circumstances can you successfully return a pointer from a function?
219
9.4. Dynamic Memory
9.4.1. Dynamic Memory Allocation
We have been creating variables on the stack, for example:
int age: // this variable is declared on the stack
Memory allocated for variable age on a stack will be de-allocated (freed) when the
function in which age is declared, finishes execution. When a program is being started,
the static memory (stack) is set aside in advance for all variables declared.
Sometimes, program may need to request a memory allocation during the running of the
program. The memory allocation during runtime of the C++ program is called dynamic
memory allocation. Dynamic memory is allocated on the heap using new key word. The
new key word returns an address for the memory allocated. Therefore, to refer to dynamic
memory, we use pointers.
To dynamically allocate memory means that a program, while running, asks the computer
to set aside a chunk of unused memory large enough to hold a variable of a specific data
type. Let’s say a program needs to create an integer variable. It will make a request to
the computer that it allocate enough bytes to store an int. When the computer fills this
request, it finds and sets aside a chunk of unused memory large enough for the variable.
It then gives the program the starting address of the chunk of memory.
The program can only access the newly allocated memory through its address, so a
pointer is required to use those bytes. C++ program requests dynamically allocated
memory through the new operator.
This statement creates a variable of type integer which is referenced by pointer ptr.
220
Once the statement executes, ptr will contain the address of the newly allocated
memory.
You can also use the new operator to dynamically create an array, for example, a 100-
element array of integers may be allocated as:
ptr = new int[100];
Example: Example showing how a value is assigned to the dynamic memory created
void func()
{
int *ptr = new int;
*ptr = 25;//This assigns 25 to heap memory referenced by ptr
//some more code
delete ptr; //remember to delete dynamic memory
}
When declaring an array, you have been required to specify the array size to allocate
correct memory space on the stack. But in practice you may not always predict the
number of items that an array will hold, for example data from the file or the database.
Such kinds of arrays are better created on the heap memory.
221
Example:
Statement below declares an array of size 5 on a heap memory.
int size = 5;
int *gradesArr = new int[size]; //create array
Example: This is an example function that would lead to leaked memory, unintentionally
by a programmer.
void func()
{
int *ptr = new int;
if (1)
return; //results in memory leak
delete ptr; /* deletion not possible as fn exits
before this line */
}
After a dynamic memory is freed, its pointer has still an address for the memory no longer
available for our program. This pointer is known as a dangling pointer. A pointer is said
to be dangling if it is pointing to a memory location that has been freed by delete key
word. Accessing a dangling pointer is trying to use memory that has already been freed
222
and returned to the heap. Such memory may already be reallocated by another new key
word.
The use of dangling pointers can cause errors in your program that are difficult to trace.
You can avoid the use of dangling pointers by setting pointers to 0 or null as soon as they
are freed.
delete ptr; //frees dynamic memory referenced by ptr
ptr = 0; //avoids pointer ptr to be dangling
int main() {
void *ptr; // void pointer
int a = 9;
return 0;
}
• Void pointer can store any address, but you must typecast before
dereferencing.
223
Dereferencing a Void Pointer
int a = 10;
void *ptr = &a;
Example
int *ptr = nullptr;
if (ptr != nullptr) {
cout << *ptr;
}
else {
cout << "Pointer is NULL";
}
int main() {
const char* names[] = {"Alice", "Bob", "Charlie"};
224
9.4.7. Const Pointers
There are three types of const pointers.
1. Pointer to Constant
• You cannot change the value, but you can change the pointer.
int var = 10;
const int *ptr = &var;
2. Constant Pointer
• You cannot change the pointer, but you can change the value.
int var = 10;
int *const ptr = &var;
2. Memory Leak
• Forgetting to free dynamically allocated memory.
int *ptr = new int[10];
// forgot delete[] ptr; memory leak
225
3. Uninitialized Pointer
• Pointer used without assigning address.
int *ptr; // garbage
*ptr = 10; // crash
Activity 9.4
What is the difference between null pointer and void pointer?
Unit summary
In this Unit, you have covered the following main points:
• The definition of a pointer as a variable of special kind which can contain a memory
address of the primary memory.
• Every variable is assigned a memory location whose address can be retrieved
using the address operator &.
• & is the reference operator and can be read as “address of” or “the address to” it
returns the address of its operand
• * is the dereference operator and can be read as “value pointed by” or “the content
of” it returns the value of its operand
• You learnt that array names can be used as pointer constants, and pointers can
be used as array names.
• Incrementing and decrementing a pointer behaves differently according to the size
of the data type to which they point.
• The memory allocation during runtime of the C++ program is called dynamic
memory allocation. The memory is allocated on the heap using new key word.
• A memory leak is said to occur in your program if after you have finished using a
block of memory allocated by new, you forget to free it via delete.
You have learnt pointers and its operations as well as dynamic memory allocation. In the
next unit we will look at structures or records which are a programmer-defined data type
that can hold many different data values.
226
UNIT
10 UNIT 10: STRUCTURES
Introduction
C++ arrays allow you to define variables that combine several data items of the same
kind, but structure is another user defined data type which allows you to combine data
items of different kinds. Structures are used to represent a record. Suppose you want to
keep track of your books in a library. You might want to track the following attributes about
each book; title, author, subject and book id. In this unit, you will learn how to group related
values that are of different types. C++ provides another structured data type, called a
struct (‘‘record’’) to group related items of different types.
Unit outcomes
By the end of this unit, you must be able to:
• Define ‘structure’
• Declare and initiate structure variables
• Assign values to structure members
• Learn about nested structures
• Discover how arrays are used in a structure
• Learn how to create an array of structure items
• Learn about the relationship between a structures and functions
Key terms
Ensure that you understand the following key terms or phrases used in this unit: structure,
structure variable, data elements, members, struct statement and nested structures.
227
10.1. Structure
A structure is a programmer-defined data type that can hold many different data values.
Group of data elements grouped together under one name. Once a structure type is
declared and its data members identified, multiple variables of this type can be created.
These data elements, known as members, can have different types and different lengths.
You declare a variable of the structure type defined. In the structure variable you can then
store all information of the particular object. A structure is also known as a record
Suppose that you want to write a program to process student data. A student record
consists of, among other things, the student’s name, student ID, courses taken, and
course grades. Thus, various components are associated with a student. However, these
components are all of different types. For example, the student’s name is a string, and
the course grades is an integer data type. Because these components are of different
types, you cannot use an array to group all of the items associated with a student. C++
provides a structured data type called struct to group items of different types.
Once a structure type is declared and its data members identified, multiple variables of
this type can be created.
228
A structure is defined as:
struct structName
{
dataType1 identifier1;
dataType2 identifier2;
.
.
.
dataTypen identifiern;
} objectName; //objectName is optional
In C++, struct is a reserved word. The members of a struct, even though they
are enclosed in braces (that is, they form a block), are not considered to form a compound
statement. Thus, a semicolon (after the right brace) is essential to end the struct
statement. A semicolon at the end of the struct definition is, therefore, a part of the
syntax.
structName: Is the structure type, a name used in declaring the variables of the
structure defined.
Within braces { }: Is the list of members of a structure. It has a type and a valid
name, the way you declare variables.
objectName: Can be a set of valid identifiers (names) for objects that have the type of
this structure. The names should be separated by a comma (,). ObjectName is optional.
Most programmers do not include object names here. They declare them when they need
them using structName.
229
Example: Define a structure to keep track of books in a library. Each book has title,
author, subject and book id attributes.
struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
} book;
Example: Declare a structure of student record from the database or file which has the
following attributes (members) Id, Name, Gender and Average.
struct Student{
int id;
string name;
char gender;
double average;
};
Activity 10.1a
Define a structure that bundles together employee number, employee name, hours
worked, pay rate and gross pay variables holding payroll data for an employee.
General Syntax:
structName variableName;
230
Using Books structure example, you can declare a variable as:
Books Book1; // Declare Book1 of type Books
Books Book2; // Declare Book2 of type Books
Using Student structure from the previous slide, you can declare (instantiate) an object
(variable) as:
Student s1; //variable s1 of type Student
The values are enumerated for the structure members in the correct sequence, separated
by commas. The data types of the values must correspond to the definition of the
members.
231
10.1.3. Structure Data Assignment
You can assign the value to the structure member using the following general syntax:
[Link] = value; //objectName is variable
Note the use of the period (.) between objectName and memberName. In C++, the dot
(.) is an operator called the member access operator.
General Syntax:
cout<< [Link]
Example:
Student s1;
// Assigning Values to Structure Members
[Link] = 02;
[Link] = “Mercy Banda”;
[Link] = ‘F’;
[Link] = 63.5;
// Accessing Structure Data
cout<<[Link]; // Displays 02
cout<<[Link]; // Displays “Mercy Banda”
cout<<[Link]; // Displays ‘F’
cout<<[Link]; // Displays 63.5
232
10.1.5. Accepting Structure Data
To accept data from the user (keyboard) into object’s members you use object name
and member name separated by a dot (.) operator.
cin>>[Link]
Example:
cin>>[Link];
cin>>[Link];
cin>>[Link];
cin>>[Link];
Activity 10.1b:
Consider the following C++ code. What is preventing it from compiling?
struct Employee {
int id;
float wage;
}
struct Costs
{
double wholesale;
double retail;
};
struct Item
{
string partNum;
string description;
Costs pricing;
};
233
The Costs structure has two double members, wholesale and retail. The Item
structure has three members. The first two, partNum and description, are string
objects. The third, pricing, is a nested Costs structure.
Notice that wholesale and retail are not members of Phone; pricing is. To access
wholesale and retail, Phone’s pricing member must first be accessed and then,
because it is a Costs structure, its wholesale and retail members can be accessed.
Note that it is the member name, not the structure name, that must be used in accessing
a member.
For example:
cout << [Link]; // wrong!
cout << [Link]; // wrong!
cout << [Link] //correct!
cout << [Link] //correct!
Activity 10.2
A Structure Date contains day, month and year. Another structure Student
contains student ID, name and date of birth. Define these two structures using
nested structure
234
10.3. Arrays and Structures
10.3.1. Arrays of structure
Structures, as any data type, can be used in creating arrays. You can also use array for
structures, the same way you use arrays of data type int, char, double, etc. If we
have 3 records of students from the database (file), we could process them by first loading
them into an array of structures where each element is a student record. For the Student
structure, we can declare array of size 3 as follows:
Student students[3];
Suppose the Student structure has four members: id, name, gender and average.
Then the members for the first element (first record) could be accessed as below:
cout<<students[0].id;
cout<<students[0].name;
cout<<students[0].gender;
cout<<students[0].average;
You can also echo/print all students records using for loop:
cout << “ID” << “\t Name” << “\t\t Age” << “\t Average” << endl;
for (int i = 0; i<3; i++)
{
cout << students[i].id << “\t” << students[i].name <<“\t”
<< students[i].age << “\t” << students[i].average << endl;
}
235
10.3.2. Pointers of Structures
For the pointers of structure data types, the members of the objects are not accessed
using a dot (.) operator but an arrow (->) operator.
Activity 10.3
What is self-referential structure?
236
Example: Using Student Structure
237
void display(const Student s[], const int n);
int main()
{
Student students[3] = {
{1,“Zanga Zatha”,‘M’,63.5},
{2,“Chikonzero Chake”,’F’,55.6},
{3,“ Alekeni Anene”, ‘M’, 68.3 },
};
display(students,3);
return 0;
}
void display(const Student s[], const int n) /*const to avoid
modifying the content of the variables */
{
for(int i=0;i<n;i++)
{
cout << s[i].id << “\t” <<s[i].name << “\t” <<s[i].gender <<
“\t” <<s[i].average << endl;
}
}
238
{
Student students[3] = {
{1,“Zanga Zatha”,‘M’,63.5},
{2,“Chikonzero Chake”,’F’,55.6},
{3,“ Alekeni Anene”, ‘M’, 68.3 },
};
Student* pStudents = &students[0];
display(pStudents,3);
return 0;
}
void display(Student *s, const int n) /*const to avoid modifying the
content of the variables*/
{
for(int i=0;i<n;i++)
{
cout <<s->id<< “\t”<< s->name << “\t” << s->gender <<
“\t” << s->average << endl;
s++;
}
}
Activity 10.4
State whether the following statements are True or False
i. Structure variables may be passed as arguments to functions.
ii. An entire structure may not be passed to a function as an argument.
iii. A function may return a structure.
10.5. Unions
A union in C++ is a user-defined data type, similar to a structure, except that all its
member variables share the same memory location. This means that only one member
of a union can store a value at any given time.
Unions are useful when a program needs to work with different types of data, but only
one type is required at a time.
239
Purpose of Unions
Unions are mainly used to:
• Conserve memory
• Store values of different data types in the same memory location
• Handle situations where only one value is active at a time
Union vs Structure
Although unions and structures look similar, they differ significantly in how memory is
allocated.
Declaration of a Union
• A union is declared just like a structure, except the keyword union is used instead
of struct.
Syntax
union UnionName {
dataType member1;
dataType member2;
};
240
Example of a Union
union Pay
{
short hours;
float sales;
};
Here:
• employee1 is a variable of type Pay
• It can store either hours or sales, but not both at the same time
241
Using Union Members
#include <iostream>
using namespace std;
union Pay {
short hours;
float sales;
};
int main() {
Pay employee1;
[Link] = 40;
cout << "Hours worked: " << [Link] << endl;
[Link] = 1250.75;
cout << "Sales amount: " << [Link] << endl;
return 0;
}
Note:
• After assigning sales, the value of hours becomes invalid, since both share the
same memory.
Initialization of Union
• Only the first member can be initialized at the time of declaration.
Pay employee1 = {40}; // initializes hours
Advantages of Unions
• Efficient use of memory
• Useful when variables represent mutually exclusive data
• Helps reduce memory footprint
• Suitable for low-level programming
242
Limitations of Unions
• Only one member can hold a valid value at a time
• Programmer must track which member is currently active
• Accessing the wrong member may lead to incorrect results
• Less safe compared to structures
Activity 10.5
i. How are unions similar to structures?
ii. How are unions different from structures?
Purpose of Enums
• Improve code readability
• Represent a fixed set of related values
• Prevent the use of invalid values
• Make programs easier to maintain
243
Enum
• An enum allows you to define a variable that can take only one value from a
predefined list.
Syntax
enum EnumName { value1, value2, value3 };
Example of Enum
#include <iostream>
using namespace std;
int main() {
Color c = RED;
• By default:
o RED = 0
o GREEN = 1
o BLUE = 2
Example
enum Days { MON, TUE, WED, THU, FRI };
244
Assigning Custom Values to Enum Constants
• You can assign specific values to enum constants.
enum Status {
SUCCESS = 1,
FAILURE = 0,
PENDING = -1
};
Example:
#include <iostream>
using namespace std;
int main() {
Status s = SUCCESS;
cout << s << endl; // Output: 1
return 0;
}
int main() {
int choice;
cout << "[Link] [Link] [Link] [Link]: ";
cin >> choice;
switch(choice) {
case ADD: cout << "Addition selected"; break;
case SUB: cout << "Subtraction selected"; break;
case MUL: cout << "Multiplication selected"; break;
case DIV: cout << "Division selected"; break;
default: cout << "Invalid choice";
}
return 0;
}
245
Enum as Function Parameters
• Enums can be passed to functions for clarity and safety.
#include <iostream>
using namespace std;
int main() {
calculate(ADD);
return 0;
}
1. Traditional Enums
• Enum values are placed in the same scope
• Can cause name conflicts
enum Status { ON, OFF };
enum Switch { ON, OFF }; // Error
Syntax
enum class Color { RED, GREEN, BLUE };
Example
#include <iostream>
using namespace std;
int main() {
Color c = Color::RED;
cout << static_cast<int>(c);
return 0;
}
246
• Advantages of enum class:
o Better type safety
o No name conflicts
o Values must be accessed using EnumName::Value
Size of Enum
• Size of enum depends on compiler
• Usually stored as an int
• Can be checked using sizeof()
cout << sizeof(Color);
Advantages of Enums
• Improves program clarity
Limitations of Enums
• Limited to predefined values
Activity 10.6
What is the difference between enum and #define?
247
Unit summary
In this Unit, you have covered the following main points:
• The definition of a structure as a programmer-defined data type that can hold many
different data values.
• To define a structure, you must use the struct statement. The struct
statement defines a new data type, with more than one member, for your program.
• A structure can be nested in another structure, the process called object
composition.
• Structures, as any data type, can be used in creating arrays.
• Structures can be sent to functions as a reference parameter, array parameter and
pointer parameter.
• A union is like a structure, except all the member variables occupy the same
memory area, so only one member can be used at a time. Unions are declared
just like structures, except the key word union is used instead of struct.
You have learnt structures which are used to create your own data type and use it to hold
values of different data types. In the next unit we will look at strings which are arrays of
characters and also different functions which we can use to manipulate strings in C++.
248
UNIT
11 UNIT 11: STRINGS MANIPULATION
Introduction
A string is a text, i.e. a sequence of characters (letters, digits and other special
characters). Actually, a string is an array that consists of a number of items, where each
item is a character in the string. A string is array of characters. Examples of characters
are a, b, c, 1, 2, 3, “, @, *, #, $, >, /, =,),}, etc. Strings are enclosed in double quotes (“ ”)
such as “abc”, “John”. There are a number of string handling functions. In this unit you
will learn common and usable string functions, like calculating the length of a string,
copying a string, concatenating strings and picking out parts of a string.
Unit outcomes
By the end of this unit, you must be able to:
• Learn about the relationship between data type int and char
• Define ‘string’
• Discuss ways of handling strings
• Explore null-terminated strings
• Explore library functions for working with C-Strings
• Learn about arrays of strings
• Understand string data type
Key terms
Ensure that you understand the following key terms or phrases used in this unit: string,
Null-terminated strings, string class, strlen, strcpy, strncpy, strcat, strcmp
and strstr.
249
11.1. Data Type Char
A char data type declares a variable that stores a single character. A character is enclosed
in single quotes (‘ ’). Normally it is used to store one character in a variable. It is declared
using char data type.
char gender;
You can assign a value to the variable as follows:
gender=‘F’; // note the use of the single quotes
You can also combine the variable declaration and assignment in a single statement as:
char gender = ‘F’;
Example
#include<iostream>
using namespace std;
int main()
{
char gender;
cout << “What is your gender?” << endl;
cout << “Enter F for Female”<< endl;
cout << “Enter M for Male”<< endl;
cout << “Enter Your Choice =>”;
cin >> gender;
if(gender==‘F’)
cout << “You are a Female”;
else if(gender==‘M’)
cout << “You are a Male”;
else
cout << “Wrong Choice”;
return 0;
}
250
11.1.1. int and char data types
Each character has internal code of the integer type, for example, the character A has the
code 65, B has 66, this goes upwards to Z. For lowercase alphabet characters, the code
starts from 97 going upwards. The code of uppercase character plus 32 gives the code
for its lowercase character.
Example:
A has code 65, therefore code for a is 65+32 (97).
The data types integers and char can cooperate as demonstrated below:
int code = 68; // ASCII Code for D
char letter;
letter = code;
cout<< letter; // Displays letter D
Activity 11.1
Write a C++ program that prompts the user for a character and prints the
corresponding character code.
251
11.2. Working with Strings
A string is array of characters. A character is a smallest building block of the string;
therefore, a string comprises one or more characters. There are two ways strings are
handles in C++; using Null-terminated strings – C-Type Strings and Using String class.
This array can hold a maximum of 9 characters since last character is \0 which is
appended automatically.
J o s o p h i n a \0
/0 indicates the end of the string
S o l o m o n \0
Note that cin only stores to array, characters from the keyboard up to where the blank
(space) is found.
Entering “John” and “John Kaunda” on a keyboard the cin will only store “John”
252
To get the whole line use [Link]() function as follows:
char fullname[20];
cout << “Enter your full name”;
[Link](fullname,19);/* 19 maximum number of characters to
be stored */
cout << fullname;
Since the string is an array, you can also print string one character at a time as below:
for(int i=0;i<19;i++)//19 assumes the name will have 19 characters
cout << fullname[i];
Activity 11.2a
Write a C++ program that prompts the user for a first name and surname and
then prints the surname then first name in one line with a space between them.
Example:
char name [10] = “John”;
//Displays 4 as the length of the string “John”
cout << “Length of the name is” << strlen(name);
253
[Link]. toupper and tolower Function – Changing String Cases
You can use toupper() and tolower() inbuilt functions found in string header to
change case of the single character. These functions return the character codes which
need to be cast to char type;
cout << toupper(‘a’); //this returns 65(code for character A)
General Syntax:
strcpy(destination_string, source_string)
Example:
char name1[]= “Elizabeth”;
char name2[10];
strcpy(name2, name1);//”Elizabeth” will be copied to name2.
cout << name2;
254
General syntax:
strncpy(string1, string2, n);
Example:
char name1[]= “Elizabeth”;
char name2[5];
strncpy(name2,name1,5);//5 is number of characters to be copies.
cout << name2; //this prints “Eliza”
General Syntax:
strcat(string1, string2);
Example:
char name1[20] = “Elizabeth”;
char name2[] = “Banda”;
strcat(name1, name2);
Cout << name1; //This prints “Elizabeth Banda”
255
than string1, it returns a negative number. If string2 is alphabetically less than
string1, it returns a positive number.
General Syntax:
strcmp(string1, string2);
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
char name1[20], name2[20];
cout <<“Enter a name =>”;
cin >> name1
cout << “Enter another name =>”;
cin >> name2;
if(strcmp(name1, name2) < 0)
cout << name1 <<endl<<name2;
else
cout << name2 <<endl <<name1;
return 0;
}
General Syntax:
strstr(string1, string2);
256
Example: Program segment to search for the string “array” inside the string
“A string is array of characters.”
In the preceding program segment strstr will locate the string “array” inside the string
“A string is array of characters.” It will return the address of the first character in “array”,
which will be stored in the pointer variable name. The segment will display:
A string is array of characters
array of characters
Declaring a string
General syntax:
string string_name;
Example:
string firstname;
It can be initialized as:
string firstname = “John”;
257
To concatenate strings, do:
firstname + surname;
e.g. cout<< firstname + surname;
Activity 11.2b
What will the following program segment display?
char dog[] = "Poppy";
cout << strlen(dog) << endl;
Note that printing names[0][1] will print a second character of the first name in an
array. This two-dimensional string array could be represented as shown in table 4.1:
258
To print one of the names, e.g. the third name (index=2):
cout << Names[2]; //Prints “Bob”
To print a single character from the matrix we must use both indexes. The statement:
cout << Names[1][4];
// Prints the character with index 4 from the name with index 1,
// i.e. ‘r’ in “Edward”.
259
Converting from String to Numeric Types (C-Style Functions)
• These functions are defined in the <cstdlib> header.
char str[10];
int x = 123;
260
Conversion Using C++ String Streams (stringstream)
• Defined in the <sstream> header.
Advantages:
• Works with C++ string
• Safer and more flexible
• Handles multiple data types
ss << num;
string str = [Link](); // "45"
int value;
ss >> value; // value = 67
261
• Works with:
o int
o float
o double
o long
2. String to Number
stoi() – String to Integer
string s = "456";
int x = stoi(s); // 456
int main() {
string str1 = "25";
string str2 = "30";
262
Activity 11.3
What will the following program segment display?
char *a[] = { "Blantyre","Karonga","Zomba", "Mangochi"};
cout << a[3] << endl;
cout << a[3][1] << endl;
Unit summary
In this Unit, you have covered the following main points:
• The definition of a string as a text, i.e. a sequence of characters (letters, digits and
other special characters), or simply as array of characters
• You learnt that char data type declares a variable that stores a single character
and that each character has internal code of the integer type.
• There are two ways of handling strings in C++; using Null-terminated strings – C-
Type Strings and Using String class.
• Null-terminated strings are stored with \0 (null character) at the end.
• The C++ library provides many functions for working with C-strings, include the
cstring header file to use these functions.
• There are functions for determining the length of a string - strlen(), for
concatenating two strings - strcat(), for copy string to another – strcpy(), for
comparing two strings - strcmp(), and for searching for the occurrence of one
string within another – strstr().
• Another way of handling string is by using string data type (string class). This way
does not require <string.h> header.
You have learnt string as an array of characters and different functions which you can
use to manipulate strings. In the next unit we will look at object-oriented programming
principles and the advantages they offer in software development.
263
UNIT
UNIT
12 12: OBJECT-ORIENTED PROGRAMMING CONCEPTS
Introduction
Object-Oriented Programming (OOP) is an essential paradigm in programming,
emphasizing the organization of code around "objects" that encapsulate data and the
methods manipulating that data. This paradigm enhances code modularity, reusability,
and maintainability. In this unit, we'll explore the core concepts that are essential for
modern software development. We'll start by breaking down the ideas of objects, classes,
and methods, setting the stage for a better understanding of how OOP works.
As we go further, we'll look into encapsulation, a useful tool for organizing and securing
your code. We'll also delve into inheritance, where you'll learn how to build a hierarchy of
classes to make your code more reusable and flexible. And to add a bit of flair, we'll
discuss polymorphism, a concept that allows one thing to take on multiple forms. By the
end of this unit, you'll not only see the advantages of OOP but also feel comfortable using
objects, classes, methods, encapsulation, inheritance, and polymorphism in your coding
adventures.
Unit outcomes
By the end of this unit, you must be able to:
• Define Object-oriented programming (OOP) and its key principles
• Differentiate between objects and classes
• Implement methods and understand their role in OOP.
• Explain the concept of encapsulation in OOP.
• Understand the importance of encapsulation in building robust and secure code.
• Implement inheritance hierarchies
• Describe polymorphism and its types
• Demonstrate the flexibility and extensibility achieved through polymorphic
behavior.
264
Key terms
Ensure that you understand the following key terms or phrases used in this unit: objects,
classes, methods, encapsulation, inheritance, polymorphism, static binding, dynamic
binding, constructor, destructor, access specifiers, base class, derived class, friend
functions, function overloading and function overriding.
The emergence of C++ was a significant milestone in this evolution. The primary intent
behind introducing the C++ programming language was to add object-oriented features
to the C language. This allowed developers to leverage the efficiency and low-level
control of C while gaining the benefits of an object-oriented approach.
265
[Link]. Characteristics of Procedure-Oriented Programming
• Emphasis on Doing Things (Algorithm): The primary focus in POP is on the
algorithm – the step-by-step instructions that the computer must follow to perform a
task. The program is essentially a list of instructions.
• Data Moves Openly: Data moves freely and openly around the system from one
function to another. There are few restrictions on which function can access or
modify which piece of data.
• Functions Transform Data: The main role of functions in POP is to transform data
from one form to another. They take input data, process it, and produce output data.
266
• Does Not Model Real-World Problems Very Well: Real-world entities often have
both attributes (data) and behaviors (functions) that are tightly coupled. POP
separates data from the functions that operate on it, which does not naturally align
with how we perceive and interact with real-world objects. This can lead to less
intuitive and harder-to-understand code.
• No Data Hiding: POP lacks mechanisms for data hiding or encapsulation. All data
is generally exposed, making it vulnerable to accidental modification by any part of
the program. This can lead to security vulnerabilities and makes it harder to maintain
the consistency of data.
• Difficulty in Maintenance and Extension: Due to global data and the lack of data
hiding, modifying or extending a POP program can be challenging. A small change
can have ripple effects throughout the entire codebase, making maintenance a time-
consuming and error-prone process.
267
• Represent Data as Objects: In OOP, real-world entities are represented as
objects that possess both attributes (data) and functions (behaviors). For
instance, a "Car" object might have attributes like color, make, model, and
functions like start(), accelerate(), brake().
• Programs Divided into Objects: Programs are no longer just a list of functions;
instead, they are composed of a collection of interacting objects. Each object is an
instance of a class and represents a real-world entity or concept.
• Functions Tied to Data Structures: Functions that operate on the data of an object
are tied together within the same data structure (the class). This close
association ensures that data is manipulated only by its authorized functions.
• Data Hiding: A crucial feature of OOP is data hiding. Data within an object is
typically hidden from external functions and can only be accessed or modified
268
through the object's own member functions. This protects data integrity and
promotes secure programming.
• New Data and Functions Can Be Easily Added: The modular nature of OOP
makes it easier to extend functionality. New data attributes and member functions
can be added to existing classes or new classes can be created without significantly
impacting the rest of the system.
[Link]. Objects
Objects are the basic run-time entities in an object-oriented system. They are
instances of classes and represent real-world entities or concepts that the program
must handle. An object combines both data (attributes) and the functions (methods) that
operate on that data.
• Real-World Representation: Objects can represent tangible entities like a
person, a place, a bank account, or a table of data. They can also represent
abstract concepts within the program.
269
• Combination of Data and Program: The term "object" signifies a cohesive unit
that encapsulates both the data (its state) and the program logic (its behavior) that
defines how it interacts with the world.
[Link]. Class
A class serves as a blueprint or a template for creating objects. It is a logical
construct that defines the common properties (data members) and behaviors (member
functions) that a group of objects will share.
• Group of Objects: A class groups objects that share common properties for their
data part and some program part. For example, all Student objects might have
name, studentID, and grade as data, and enroll(), submitAssignment(),
displayInfo() as functions.
• User-Defined Data Type: In essence, a class is a new user-defined data type.
Once a class is defined, you can declare variables of that class type, which are
then called objects.
270
• Data Not Accessible to Outside World: The data within an encapsulated unit
(class) is not directly accessible to the outside world.
• Access through Functions: Only those functions which are wrapped within the
class can access and manipulate its data. These functions provide the controlled
interface between the object's data and the rest of the program. This mechanism is
crucial for data integrity and security.
[Link]. Inheritance
Inheritance is a mechanism that allows a class to inherit properties and behaviors
from another class. It establishes an "is-a" relationship between classes, where a
derived class (child) acquires the characteristics of a base class (parent).
• Promotes Code Reusability: Inheritance is a powerful tool for code reusability, as
common functionalities can be defined once in a base class and then reused by
multiple derived classes.
[Link]. Polymorphism
Polymorphism literally means "the ability to take more than one form." In OOP, it
refers to the ability of an operation or function to exhibit different behaviors depending on
the type of data or object it is operating on.
• Different Instances of an Operation: An operation (like draw()) may exhibit
different instances. For example, draw() for a Circle object will draw a circle, while
draw() for a Square object will draw a square. The behavior depends upon the
type of data (object) used in the operation.
271
[Link]. Dynamic Binding
Binding refers to the association of a procedure call with the code that will be
executed in response to that call.
• Runtime Resolution: Dynamic binding (also known as late binding or runtime
binding) means that the code associated with a given procedure call is not known
until the time of the call at run-time.
272
• Each object encapsulates a specific functionality and data, making it easier to
understand, develop, debug, and maintain individual components. This leads to a
more organized and less overwhelming codebase.
2. Reusability
• The core concepts of classes and inheritance are central to facilitating code reuse.
• Once a class is defined, it can be used to create multiple objects (instances) without
rewriting the code. Furthermore, subclasses can inherit and extend the
functionalities of their parent classes, allowing developers to build upon existing,
tested code rather than starting from scratch. This significantly reduces
development time and potential errors.
development.
• New classes can be created based on existing ones, and modifications or
enhancements can be made to individual classes without affecting the entire
codebase. This makes it significantly easier to adapt to changing requirements, add
new features, or integrate new components into an existing system.
4. Maintainability
• The principles of encapsulation and abstraction are key contributors to improved
code maintainability.
• Because the internal implementation details of a class are hidden, changes to these
internals do not impact the external code that uses that class. This reduces the risk
of introducing bugs during maintenance activities and allows for easier updates and
bug fixes without widespread code modifications.
273
it simulates is enhanced. This direct mapping makes the code more
understandable, relatable, and easier to reason about for developers.
Some promising and established areas for the application of OOP include:
1. Real-time Systems: Systems that require immediate responses to events, such
as industrial control systems, robotics, and embedded systems, benefit from
OOP's modularity and ability to model concurrent processes.
274
5. AI and Expert Systems: Artificial intelligence applications, including expert
systems that mimic human decision-making, often use OOP to represent
knowledge and reasoning components as interacting objects.
Activity 12.1
How does encapsulation contribute to the modularity of code in OOP?
275
• Object: An object is an instance of a class. While a class defines the structure
and behavior, no memory is allocated when a class is merely defined. Memory is
only allocated and a concrete entity comes into existence when an object of that
class is created. Continuing the cookie cutter analogy, an object is an actual cookie
created using the cookie cutter.
Example:
class Student {
// This is the class definition.
// It defines what a 'Student' will look like (e.g., name, age, grade)
// and what actions a 'Student' can perform (e.g., displayInfo()).
// At this point, no memory is allocated for any specific student.
};
// Student is a class. No memory is allocated until we create an object of
//this class.
• A New Data Type: When we define a class, we are essentially creating a new user-
defined data type. This new data type can then be used to declare variables
(objects) just like built-in data types (e.g., int, float, char). This allows for highly
specialized and domain-specific data representations.
• Encapsulation and Data Hiding: A key feature of classes is their ability to allow
data to be hidden from external use, if necessary. This is achieved through access
specifiers (which we'll discuss shortly). By bundling data and functions together and
controlling access, classes promote encapsulation, a core OOP principle that
protects data integrity.
276
• Abstract Data Type (ADT): When defining a class, we are effectively creating a
new abstract data type (ADT). An ADT defines a set of data and a set of operations
that can be performed on that data, without specifying how the data is stored or how
the operations are implemented. Classes provide a concrete way to implement
ADTs in C++.
ii. Class Function Definition: The class function definition describes how the class
functions are implemented. This is where you write the actual code for the
member functions declared in the class declaration. These definitions can be placed
either inside or outside the class declaration.
Basic Syntax:
class ClassName {
// Access specifiers (public, private, protected)
// Data members (attributes)
// Member functions (methods)
};
277
Detailed Syntax with Access Specifiers:
class ClassName {
private:
// Private variable declarations;
// Private function declarations;
public:
// Public variable declarations;
// Public function declarations;
protected:
// Protected variable declarations;
// Protected function declarations;
};
In this example, the Student class has three data members: name (a string), age (an
integer), and grade (a float). It also has one member function, displayInfo(), which
prints the values of these data members to the console. All members are declared
public, meaning they can be directly accessed from outside the class.
278
12.2.4. Access Specifiers
Access specifiers are keywords in C++ that define the visibility and accessibility of
class members (data members and member functions). They are crucial for
implementing encapsulation and data hiding. There are three primary access specifiers
in C++:
i. public:
o Members declared as public are accessible from outside the class.
o Any part of the program can directly access or modify public members using
an object of the class.
o Public members form the interface of the class, through which other parts of
the program interact with the object.
ii. private:
o Members declared as private cannot be accessed or viewed from outside
the class.
o They are only accessible by other member functions of the same class.
o By default, all members of a class are private if no access specifier is explicitly
provided. This is a strong mechanism for data hiding.
iii. protected:
o Members declared as protected are similar to private members in that they
cannot be accessed directly from outside the class.
o However, protected members can be accessed by derived classes (classes
that inherit from the current class). This is particularly relevant in the context
of inheritance.
279
[Link]. Access Specifiers - Example
Consider the Student class modified to use private and public access specifiers:
class Student {
private: // Private members: accessible only within the class
string name;
int age;
float grade;
In this example:
• name, age, and grade are private. This means you cannot directly write
[Link] = “Alice”; from main().
280
12.2.5. Creating Objects
As mentioned, an object is an instance of a class. Once a class is defined, we can create
multiple objects of that class. Each object will have its own copy of the class’s data
members.
Example:
// Assuming the Student class is defined as above
int main() {
Student x; // Creates a variable 'x' of type Student
// 'x' is now an object of the Student class.
// It has its own 'name', 'age', and 'grade' data members.
// You can also create multiple objects:
// Student y, z; // Creates objects y and z of type Student
return 0;
}
The class variables are commonly known as objects. Therefore, in the example, x is
called an object of type Student. Each object (x, y, z) will have its own independent set
of name, age, and grade variables.
• public members (both data and functions) can be accessed directly using the dot
operator.
281
Example:
/* Assuming the Student class with private data and public
methods is defined */
int main() {
Student student1; // Creating an object of the Student class
return 0;
}
In this example, student1 is an object of the Student class. We access its public member
functions setDetails() and displayInfo() using the dot operator (.). These public
functions then internally handle the access and manipulation of the private data members
(name, age, grade).
[Link]. Constructor
• A constructor is a special member function that is automatically called when
an object is created.
• Its primary purpose is to initialize the object's data members to a valid state.
This prevents objects from being created with garbage or uninitialized values.
• Constructors have the same name as the class itself.
• They do not have a return type, not even void.
282
Constructor Syntax:
class ClassName {
public:
ClassName(parameters) { // Constructor definition
// Constructor code to initialize data members
}
};
Constructor - Example
class Student {
private:
string name;
int age;
float grade;
public:
// Constructor with parameters
Student(string n, int a, float g) {
name = n; // Initialize name
age = a; // Initialize age
grade = g; // Initialize grade
cout << "Constructor called for " << name << endl;
}
void displayInfo() {
cout << "Name: " << name << endl;
cout << "Age: " << age << endl;
cout << "Grade: " << grade << endl;
}
};
int main() {
// Object with parameterized constructor
// The constructor Student("John Zathu", 21, 92.3) is
//automatically called here
Student student1("John Zathu", 21, 92.3);
[Link]();
return 0;
}
283
[Link]. Types of Constructors
C++ supports different types of constructors to handle various object creation scenarios:
i. Default Constructor:
o A constructor that takes no parameters.
o If you do not define any constructor for your class, the C++ compiler
automatically provides a public default constructor. This default constructor
performs default initialization for built-in types and calls default constructors
for class type members.
o If you define any other constructor (e.g., a parameterized constructor), the
compiler will not automatically provide a default constructor. In such cases, if
you need a default constructor, you must define it explicitly.
284
Types of Constructors - Example
class Student {
private:
string name;
int age;
float grade;
public:
// i. Default Constructor
Student() {
name = "Hazel Fadah";
age = 21;
grade = 76.6;
cout << "Default Constructor called." << endl;
}
// ii. Parameterized Constructor
Student(string n, int a, float g) {
name = n;
age = a;
grade = g;
cout<<"Parameterized Constructor called for "<<name<< endl;
}
// iii. Copy Constructor
// Takes a const reference to another Student object
Student(const Student &s) {
name = [Link];
age = [Link];
grade = [Link];
cout << "Copy Constructor called for " << name << endl;
}
void displayInfo() {
cout << "Name: " << name << endl;
cout << "Age: " << age << endl;
cout << "Grade: " << grade << endl;
cout << "--------------------" << endl;
}
};
// Using Constructors
int main() {
// Calls Default Constructor
Student student1;
[Link]();
// Calls Parameterized Constructor
Student student2("Joseph Waka", 22, 85.6);
[Link]();
//Calls Copy Constructor:student3 is initialized as a copy of student2
Student student3 = student2;//or Student student3(student2);
[Link]();
return 0;
}
285
[Link]. Destructor
• A destructor is a special member function that is automatically called when an
object goes out of scope or is explicitly destroyed (e.g., using delete for
dynamically allocated objects).
• Its primary purpose is to clean up resources that the object might have acquired
during its lifetime, such as dynamically allocated memory, file handles, or network
connections.
• Destructors have the same name as the class, prefixed with a tilde (~).
• They do not take any parameters and do not have a return type. A class can
have only one destructor.
Destructor Syntax:
class ClassName {
public:
~ClassName() { // Destructor definition
// Destructor code to release resources
}
};
Destructor - Example
class Student {
private:
string name;
int age;
float grade;
public:
Student(string n, int a, float g) {
name = n;
age = a;
grade = g;
cout << "Constructor called for " << name << endl;
}
~Student() { // Destructor
cout << "Destructor called for " << name << endl;
// In a real application, you might deallocate memory here
}
286
void displayInfo() {
cout << "Name: " << name << endl;
cout << "Age: " << age << endl;
cout << "Grade: " << grade << endl;
}
};
// Using Destructor
int main() {
// Object student1 is created, constructor is called
Student student1("Jane Zatha", 21, 92.3);
[Link]();
// When main() finishes, student1 goes out of scope, and its
//destructor is automatically called.
return 0;
}
In this example, when the main() function finishes execution, the student1 object goes
out of scope. At that precise moment, its destructor ~Student() is automatically invoked,
and the message "Destructor called for Jane Zatha" will be printed to the
console.
287
[Link]. Defining Member Functions Inside the Class
When a member function is defined inside the class definition, it is implicitly treated as an
inline function by the compiler. This can sometimes lead to performance optimizations for
small functions.
288
Member Functions in Classes - Example (Outside the class)
class Student {
private:
string name;
int age;
float grade;
public:
// Function declarations inside the class
void setDetails(string n, int a, float g);
void displayInfo();
};
void Student::displayInfo() {
cout << "Name: " << name << endl;
cout << "Age: " << age << endl;
cout << "Grade: " << grade << endl;
}
This approach separates the interface (declarations in the class) from the implementation
(definitions outside the class), which can improve code organization, especially in larger
projects where declarations might be in header files (.h or .hpp) and definitions in source
files (.cpp).
289
12.2.9. Objects as Function Arguments
Just like built-in data types, objects can be passed to functions as arguments. This
allows functions to operate on specific objects. Objects can be passed in three ways:
• By Value: A copy of the object is passed to the function. Changes made to the
copy inside the function do not affect the original object.
• By Reference: A reference to the original object is passed. Changes made to the
object inside the function do affect the original object. This avoids the overhead of
copying large objects.
• By Pointer: A pointer to the original object is passed. Similar to pass-by-
reference, changes made through the pointer affect the original object.
int main() {
Student student1("Mercy Zathu", 22, 91.5);
displayStudent(student1);//student1 object is passed by value
return 0;
}
290
When student1 is passed by value to displayStudent(), a new Student object s
is created as a copy of student1. The displayStudent() function then operates on
this copy.
Example:
class Student {
private:
string name;
int age;
float grade;
public:
Student(string n, int a, float g) : name(n), age(a),
grade(g) {}
void displayInfo() {
cout << "Name: " << name << endl;
cout << "Age: " << age << endl;
cout << "Grade: " << grade << endl;
}
};
// Function that creates and returns a Student object
Student createStudent() {
// A local Student object is created
Student studentTemp("Jolly Banda", 25, 94.2);
//The object is returned by value (a copy is made)
return studentTemp;
}
int main() {
// The object returned by createStudent() is used to initialize
'student'
Student student = createStudent();
[Link]();
return 0;
}
291
In this example, createStudent() constructs a Student object studentTemp locally
and then returns a copy of it. This returned copy is then used to initialize the student
object in main().
292
void displayInfo() {
//Can also use 'this->' for clarity,though not strictly necessary here
cout << "Name: " << this->name << endl;
cout << "Age: " << this->age << endl;
cout << "Grade: " << this->grade << endl;
}
};
int main() {
Student student1;
[Link]("John Waka", 24, 87.9);
[Link]();
return 0;
}
In setDetails(), this->name refers to the name data member of the Student object,
while name (without this->) refers to the function parameter.
293
[Link]. Static Member Functions
• Access Static Members Only: Static member functions can only access static
data members and other static member functions of the class. They cannot
access non-static (instance-specific) data members or functions because they are
not associated with a particular object.
• Declaration: They are also declared with the static keyword inside the class
definition.
• Called Using Class Name: Static member functions can be called directly using
the class name and the scope resolution operator (e.g.,
ClassName::staticFunction()) without needing an object of the class.
294
int Student::studentCount = 0;
int main() {
// Access static member function using class name
cout << "Initial total students: " <<
Student::getStudentCount() << endl; // Output: 0
return 0;
}
In this example, studentCount keeps track of the total number of Student objects
created. It's a single variable shared across all Student objects. getStudentCount()
is a static member function that provides a way to access this shared count without
needing a specific Student object.
Syntax:
ReturnType FunctionName(parameters) const {
// Function body
// Cannot modify any non-static data members of the object
}
295
• Purpose:
o Data Integrity: They ensure that the object's state remains unchanged.
o Overloading: You can overload member functions based on their const-
ness.
o const Objects: Only const member functions can be called on const
objects.
296
// Const member function: does not modify the object
void displayInfo() const {
cout << "Name: " << name << endl;
cout << "Age: " << age << endl;
cout << "Grade: " << grade << endl;
// name = "New Name"; // ERROR: Cannot modify 'name' in
//a const function
}
};
int main() {
// Creating a Student object and setting its details
Student student1("", 0, 0.0);//Initialize with default values
// Calls non-const setter
[Link]("John Waka", 24, 87.9);
[Link](); // Calls const displayer
return 0;
}
In this example, displayInfo() is a const member function, guaranteeing that it will not
alter the name, age, or grade of the Student object. This allows it to be safely called
on const objects like student2. In contrast, setDetails() is not const because its
purpose is to modify the object's state.
Activity 12.2
What is the purpose of a constructor in a C++ class? Provide examples of both a
default constructor and a parameterized constructor
297
12.3. Inheritance
Inheritance is one of the foundational pillars of Object-Oriented Programming (OOP),
alongside encapsulation, polymorphism, and abstraction. At its core, inheritance allows a
new class to derive properties and behaviors (methods) from an existing class. This
means that a new class can acquire the data members (variables) and member functions
(methods) of another class, establishing a hierarchical relationship between them.
Key Terminology:
• Base Class (Parent Class / Superclass): The existing class from which other
classes inherit. It serves as the foundation.
• Derived Class (Child Class / Subclass): The new class that inherits from the
base class. It extends or specializes the functionality of the base class.
The "is-a" relationship is crucial in understanding inheritance. If Class B "is a" Class A,
then Class B can inherit from Class A. For example, a Car "is a" Vehicle, so Car can
inherit from Vehicle.
1. Single Inheritance
Single inheritance is the simplest form of inheritance, where a class is derived from only
one base class. This creates a straightforward parent-child relationship.
298
Example:
class Student {
// Base class code:
// Data members like name, studentID
// Member functions like setStudentInfo(), displayStudentInfo()
};
class Grades : public Student {
// Derived class code:
// Can access public and protected members of Student
// Can add its own data members like grade
//Can add its own member functions like setGrade(), displayGrade()
};
In this example, the Grades class inherits from the Student class. This means an object
of Grades will have all the public and protected members of Student in addition to its
own members.
2. Multiple Inheritance
Multiple inheritance occurs when a class is derived from more than one base class.
This allows a derived class to combine functionalities from multiple independent base
classes.
Example:
class Attendance {
protected:
int daysPresent;
public:
void setAttendance(int days) {
daysPresent = days;
}
void displayAttendance() {
cout << "Attendance: " << daysPresent << " days" << endl;
}
};
299
Here, the StudentGrades class inherits from both Student and Attendance classes.
An object of StudentGrades will possess members from both Student and
Attendance, along with its own grade member. This can be useful when a class logically
"is a" combination of two or more distinct entities.
3. Multilevel Inheritance
Multilevel inheritance occurs when a class is derived from another derived class. This
forms a chain of inheritance, where one class acts as a base class for another, which in
turn acts as a base class for a third, and so on.
Example:
class Student {
// Base class code (e.g., name, studentID, displayStudentInfo())
};
In this structure, TestScores is derived from Grades, which itself is derived from
Student. This means TestScores inherits members from both Grades and Student.
300
4. Hierarchical Inheritance
Hierarchical inheritance occurs when multiple classes are derived from a single base
class. This creates a tree-like structure where one parent class has multiple children.
Example:
class Student {
// Base class code (e.g., name, studentID)
};
Here, both Sports and Arts classes inherit independently from the Student class.
They share the common characteristics of a Student but also have their own
specialized attributes and behaviors.
301
5. Hybrid Inheritance
Hybrid inheritance is a combination of more than one type of inheritance, such as
single, multiple, and multilevel inheritance. This allows for complex and flexible class
hierarchies that model real-world relationships more accurately.
Example:
class Person {
protected:
string name;
int age;
};
int main() {
Test student;
[Link]("Alice Waya", 19, 202, 88);
[Link]();
return 0;
}
302
This example demonstrates a hybrid inheritance where Test inherits from Student
(multilevel), and Student inherits from Person (single). If we were to add another base
class to Test (e.g., Exam), it would become a combination of multilevel and multiple
inheritance, forming a hybrid structure.
Example:
class Student {
protected:
string name;
int studentID;
public:
// Parameterized constructor for Student
Student(string n, int id) : name(n), studentID(id) {
cout << "Student Constructor Called" << endl;
}
void displayStudentInfo() {
cout<< "Name: " << name << ", Student ID: "<<studentID<< endl;
}
};
303
void displayGrade() {
displayStudentInfo(); // Call base class function
cout << "Grade: " << grade << endl;
}
};
int main() {
Grades studentGrades("Jane Doe", 456, 'B');
// Output:
// Student Constructor Called
// Grades Constructor Called
[Link]();
return 0;
}
304
Example – Composition
Grade Class
class Grade {
private:
float marks;
public:
Grade(float m) {
marks = m;
}
char getLetterGrade() {
if (marks >= 80) return 'A';
else if (marks >= 60) return 'B';
else if (marks >= 50) return 'C';
else return 'F';
}
};
class Student {
private:
int id;
string name;
Grade grade; // Composition
public:
Student(int i, string n, float m) : grade(m) {
id = i;
name = n;
}
void showStudent() {
cout << "Name: " << name << endl;
cout << "Grade: " << [Link]() << endl;
}
};
305
Table 12.2: Key Differences: Inheritance vs Composition
Feature Inheritance Composition
Relationship IS-A HAS-A
Reusability High High
Flexibility Less More
Dependency Weak Strong
Example ExamStudent IS-A Student Student HAS-A Grade
Scenario:
• Class A (Base Class)
• Class B inherits from A
• Class C inherits from A
• Class D inherits from both B and C
306
Without virtual inheritance, D would contain two separate A sub-objects (one via B and
one via C), leading to ambiguity when accessing members of A directly from D.
Syntax:
class DerivedClass : virtual public BaseClass {
// ...
};
Example:
// Virtual Base Class
class Person {
protected:
string name;
public:
Person(string n) : name(n) {}
void displayName() {
cout << "Name: " << name << endl;
}
};
307
Employee(string n) : Person(n) {}
void displayEmployeeStatus() {
cout << name << " is an employee." << endl;
}
};
void displayStatus() {
displayName(); // No ambiguity due to virtual inheritance
displayStudentStatus(); // From Student
displayEmployeeStatus(); // From Employee
}
};
int main() {
WorkingStudent ws("Alice");
[Link]();
// Output:
// Name: Alice
// Alice is a student.
// Alice is an employee.
return 0;
}
If both base classes (e.g., Student and Employee) have a member with the same name
that originated from the virtual base class (e.g., name from Person), and you need to
308
access it directly from the most derived class (WorkingStudent), you can use scope
resolution (e.g., Person::name) to explicitly specify which member you are referring
to, although with virtual inheritance, this ambiguity is often resolved automatically as
there's only one instance.
Example:
class Animal {
public:
virtual void makeSound() {
cout << "Animal makes a sound" << endl;
}
};
309
int main() {
Animal* myAnimal;
Dog myDog;
Cat myCat;
myAnimal = &myDog;
myAnimal->makeSound(); //Calls Dog's makeSound()- Dynamic Dispatch
myAnimal = &myCat;
myAnimal->makeSound(); //Calls Cat's makeSound()- Dynamic Dispatch
return 0;
}
310
Example:
class Student {
public:
virtual void display() {
cout << "Displaying student information" << endl;
}
};
int main() {
Student* sPtr;
Grades gObj;
sPtr = &gObj;
sPtr->display(); // Calls Grades::display() due to polymorphism
return 0;
}
If you were to accidentally misspell display as dispaly in Grades without override, the
compiler would treat it as a new function, not an override, leading to unexpected behavior.
With override, the compiler would flag it as an error, helping you identify the mistake
immediately.
311
Syntax:
virtual ReturnType FunctionName(parameters) = 0;
Example:
// Abstract base class
class Student {
protected:
string name;
int studentID;
public:
Student(string n, int id) : name(n), studentID(id) {}
312
}
};
int main() {
// Student s; // ERROR: Cannot instantiate an abstract class
Grades student("John Banda",123,'A');//OK:Grades is a concrete class
[Link]();
return 0;
}
313
Example:
class Student {
protected: // Accessible by derived classes
string name;
int studentID;
public:
void setStudentInfo(string n, int id) {
name = n;
studentID = id;
}
};
int main() {
Grades student;
[Link]("John Banda", 123);
[Link]('A');
[Link]();
//cout << [Link];// ERROR: 'name' is protected, inaccessible
return 0;
}
In this example, the Grades class can directly access name and studentID from the
Student class because they are declared as protected. However, an object of Grades
(like student in main) cannot directly access [Link] from outside the class,
demonstrating the protected access control.
314
12.3.7. Friend Functions and Classes
Sometimes, it's necessary for a non-member function or another class to have access to
the private and protected members of a class. C++ provides friend mechanisms for this.
Example:
class Student {
private:
string name;
int age;
public:
Student(string n, int a) : name(n), age(a) {}
// Friend function declaration
friend void displayStudentDetails(Student s);
};
int main() {
Student student1("Mike Phiri", 24);
// Calls friend function
displayStudentDetails(student1);
return 0;
}
315
[Link]. Friend Class
A friend class is a class whose members have access to the private and protected
members of another class. If Class A declares Class B as its friend, then all member
functions of Class B can access the private and protected members of Class A.
Example:
class Student; // Forward declaration for Grade class
class Grade {
public:
void displayStudentGrade(Student &s); // Member function of Grade
};
class Student {
private:
string name;
int grade;
public:
Student(string n, int g) : name(n), grade(g) {}
// Friend class declaration
friend class Grade; // Grade class is a friend of Student
};
int main() {
Student student1("Tom Banda", 90);
Grade gradeObj;
[Link](student1);
return 0;
}
316
12.3.8. Benefits of Inheritance
Inheritance is a powerful feature of OOP that offers several significant advantages:
1. Code Reusability
• Inheritance allows the reuse of code, as common functionalities can be
implemented once in a base class and then inherited by multiple derived classes.
This avoids duplicating code, which saves development time and reduces the
chances of errors.
• Instead of rewriting similar methods for different but related classes, you can simply
inherit them, promoting a "Don't Repeat Yourself" (DRY) principle.
2. Polymorphism
• Inheritance enables polymorphic behavior, allowing objects of derived classes to
be treated as objects of the base class. This provides immense flexibility and
dynamic method binding.
• Through virtual functions, you can write generic code that operates on base class
pointers or references, and at runtime, the appropriate derived class method will be
invoked. This is crucial for designing extensible and adaptable systems.
3. Organized Code
• Inheritance helps in organizing classes into a hierarchy, making it easier to
4. Maintenance Efficiency
• Changes made to the base class automatically affect all derived classes. This
317
5. Encapsulation
• Inheritance supports encapsulation by allowing the implementation details of a
base class to be hidden from derived classes (via private members), while still
exposing necessary functionalities (via protected or public members). This
promotes data abstraction and modular design.
• Derived classes interact with the base class through its defined interface, without
needing to know the internal workings of the base class.
6. Consistency
• Inheritance promotes consistency by ensuring that derived classes adhere to a
common interface or set of behaviors defined by the base class.
• This ensures that all derived classes follow the same structure and behavior for
inherited functionalities, leading to more predictable and uniform code across the
application. For example, if a Vehicle base class defines a startEngine()
method, all derived classes like Car, Motorcycle, and Truck will have this
method, ensuring consistent behavior for starting their engines.
Activity 12.3
a. Explain the concept of constructor and destructor execution order in
inheritance.
b. Explain the diamond problem in multiple inheritance and how virtual
inheritance resolves it.
12.4. Polymorphism
Polymorphism is one of the most powerful and fundamental concepts in Object-Oriented
Programming (OOP), alongside encapsulation, inheritance, and abstraction. The term
"polymorphism" originates from Greek words: "poly" meaning many, and "morph"
meaning forms. Therefore, polymorphism literally translates to "many forms."
318
In the context of C++, polymorphism allows one entity (like a function or an object) to
behave in different ways, depending on the context in which it is used. This means
that a single interface can be used to represent various underlying types or
implementations. This capability significantly enhances the flexibility, extensibility, and
reusability of code in object-oriented systems.
These two types of polymorphism dictate when the decision about which function or
operation to execute is made – either during the compilation phase or during the
program's execution.
319
This type of polymorphism is resolved during the compilation phase, making it highly
efficient as there is no overhead during runtime to determine which function to execute.
Compile-time polymorphism in C++ is primarily achieved through two main mechanisms:
a. Function Overloading
b. Operator Overloading
a. Function Overloading
Function overloading allows multiple functions to have the same name but differ in
their signature. The signature of a function is determined by:
• The number of parameters.
• The type of parameters.
• The order of parameters (if types are different).
The compiler determines the appropriate function to call based on the number and types
of arguments passed during the function call. This process is known as overload
resolution.
class Student {
public:
// Function to calculate total marks for integer values
int totalMarks(int assignment, int exam) {
return assignment + exam;
}
320
}
int main() {
Student student;
return 0;
}
In this example, the totalMarks function is overloaded. The C++ compiler analyzes the
arguments provided in each call to totalMarks and matches it with the most appropriate
function signature at compile time.
b. Operator Overloading
Operator overloading allows us to define how standard C++ operators (like +, -, *, /, ==,
<<, >>, etc.) behave for user-defined types (classes). This enables operators to work
321
with objects of your custom classes in a natural and intuitive way, similar to how they work
with built-in data types.
It allows you to define custom behaviors for operators in the context of a class.
class Student {
public:
int marks;
int main() {
Student s1(75); // Student object with 75 marks
Student s2(85); // Student object with 85 marks
322
// Output: 160
cout << "Total Marks after addition: " << [Link] << endl;
In this example, the + operator is overloaded for the Student class. When s1 + s2 is
encountered, the compiler calls the operator+ member function of s1, passing s2 as an
argument. This binding is resolved at compile time.
a. Virtual Functions
A virtual designed function is a function in a base class that is declared with the virtual
keyword. It is to be overridden in derived classes.
• Enabling Dynamic Binding: Virtual functions are the key to achieving run-time
polymorphism in C++. They enable dynamic binding, meaning that the appropriate
323
function to be called is determined at runtime based on the actual type of the
object pointed to by a base class pointer or reference, rather than the type of the
pointer or reference itself.
• Syntax: The virtual keyword is used to declare a function as virtual in the base
class.
// Derived class
class GraduateStudent : public Student {
public:
// Overriding the virtual function from the base class
//'override' keyword (C++11 onwards) is good practice for clarity
// and error checking
void displayGrade() override {
cout<<"Derived class: Grade for Graduate Student is A." << endl;
}
};
int main() {
Student* s; // A pointer to the base class (Student)
324
GraduateStudent gs;
UndergraduateStudent ugs;
o Syntax:
virtual ReturnType FunctionName(parameters) = 0;
325
• Blueprint for Derived Classes: It provides a blueprint or an interface that derived
classes must implement. Any derived class that wants to be concrete (i.e.,
instantiable) must provide an implementation for all inherited pure virtual functions.
If a derived class does not override all pure virtual functions, it also becomes an
abstract class.
326
int main() {
// Student s; // ERROR: Cannot instantiate an abstract class
UndergraduateStudent ugs;
PostgraduateStudent pgs;
// Pointers to the abstract base class can point to derived class objects
Student* s1 = &ugs;
Student* s2 = &pgs;
// Can call common (non-pure virtual) functions through base class pointer
s1->commonStudentInfo();//Output: This is common student information.
return 0;
}
327
• Memory Leaks Without Virtual Destructor: Without a virtual destructor in the
base class, when you delete an object via a base class pointer, only the base class
destructor is called. This can lead to memory leaks or incomplete destruction of
derived class objects, as the derived class's specific cleanup logic is never
executed.
• Rule of Thumb: Always declare destructors as virtual in base classes when they
are intended to be used polymorphically (i.e., when you expect to delete derived
class objects through base class pointers).
class Base {
public:
// Virtual destructor
virtual ~Base() {
cout << "Base Destructor\n";
}
};
int main() {
// Dynamically allocate a Derived object and point to it with a Base pointer
Base* ptr = new Derived();
/*
328
Expected Output:
Derived Destructor
Base Destructor
*/
return 0;
}
class AbstractBase {
public:
// Pure virtual destructor - must have an implementation
virtual ~AbstractBase() = 0;
};
329
cout << "Derived Destructor\n";
}
};
int main() {
// Dynamically allocate a Derived object through an AbstractBase pointer
AbstractBase* ptr = new Derived();
/*
Expected Output:
Derived Destructor
AbstractBase Destructor
*/
return 0;
}
If you are designing an abstract base class meant to be inherited by other classes, always
make the destructor virtual to ensure proper cleanup of derived objects, regardless of
whether it's a pure virtual destructor or a regular virtual destructor.
330
2. Flexibility
• Polymorphism provides immense flexibility by allowing a common interface for
different types of objects. This makes the code easier to maintain and extend,
as you can interact with diverse objects through a unified set of operations.
• For example, a Shape base class with a draw() method can have Circle,
Square, and Triangle derived classes. You can then have a collection of
Shape pointers and call draw() on each, and the correct draw() method for
each specific shape will be invoked.
3. Extensibility
• New functionality can be added with minimal changes to the existing code,
4. Maintainability
• By implementing polymorphism, developers can focus on a general framework
(the base class interface) while deferring specific implementations to derived
classes. This separation of concerns makes the code significantly easier to
maintain and update.
• Changes to the internal implementation of a derived class do not affect the code
that uses the base class interface, reducing the risk of introducing bugs and
simplifying debugging.
5. Dynamic Binding
• In runtime polymorphism, the function to be invoked is determined at runtime,
enabling more flexible and reusable code. This dynamic decision-making allows
programs to adapt to different situations and object types during execution,
leading to more powerful and adaptable software.
331
In summary, polymorphism helps in designing flexible and maintainable code by allowing
objects to take many forms and perform different actions based on their types, making
C++ a powerful language for complex software development.
Activity 12.4
a. How does method overriding differ from method overloading?
b. What is a virtual destructor, and why is it important in polymorphic base
classes?
12.5. Encapsulation
While the primary focus of this chapter is polymorphism, it's important to understand
how other OOP principles, especially encapsulation, work hand-in-hand with it.
Encapsulation is one of the fundamental principles of object-oriented programming
(OOP) that helps in organizing and structuring code. It involves bundling the data
(attributes) and the methods (functions) that operate on the data into a single unit
known as a class.
• The class serves as a blueprint for creating objects, and encapsulation restricts
access to certain components of the class, providing a level of data hiding and
abstraction.
• Encapsulation is the practice of keeping the data (attributes) private and providing
public methods (often called getters and setters) to access and modify that data.
This ensures control over the values and maintains data integrity, which leads to
better data protection.
• Controlled Access: Public functions (getters and setters) can be provided for
controlled access to private variables. This allows the class to validate input,
332
perform necessary operations before setting data, or format output before
returning data.
333
• Member Functions: Methods within a class that perform operations on the data
members. They can be public to allow external code to interact with the class in a
controlled manner.
o Example:
class Circle {
private:
double radius;
public:
// Setter for radius
void setRadius(double r) {
radius = r;
}
// Function to calculate the area of the circle
double calculateArea() {
return 3.14159 * radius * radius;
// Using M_PI for better precision if available
}
};
int main() {
Circle circle1;
double radius;
cout << "Enter the radius of the circle: ";
cin >> radius;
[Link](radius);
cout << "The area of the circle is: " <<
[Link]() << endl;
return 0;
}
• Constructor: Special member functions used for initializing the object's state when
it is created. They can be used to set initial values for data members, ensuring
objects are created in a valid state.
o Example:
class Person {
private:
string name;
int age;
public:
// Constructor
Person(string n, int a) : name(n), age(a) {}
// other member functions
};
334
12.5.3. Encapsulation vs. Data Hiding
Encapsulation is often confused with data hiding, but they are related yet distinct
concepts:
• Encapsulation: Refers to the bundling of data and methods that operate on
that data into a single unit (a class). It's the packaging mechanism.
• Data Hiding: Specifically refers to restricting access to certain components
(data members) of the class, typically by making them private. It's the mechanism
of protection.
Think of it this way: Encapsulation is the act of putting all the related parts of a machine
into a single casing. Data hiding is making sure that only specific buttons or levers on that
casing can be used to operate the machine, and you can't just reach inside and mess
with the gears directly.
Example:
class Student {
private:
string name; // Encapsulated data (private) - Data Hiding
int grade; // Encapsulated data (private) - Data Hiding
public:
// Constructor to initialize name and grade
Student(string studentName, int studentGrade) {
name = studentName;
setGrade(studentGrade); // Using setter to assign grade,
// demonstrating controlled access
}
335
if (studentGrade >= 0 && studentGrade <= 100) {
grade = studentGrade;
} else {
cout<<"Invalid grade. Please enter a value between 0-100."<< endl;
}
}
// Method to display student details
void displayStudentInfo() const {
cout << "Student Name: " << name << endl;
cout << "Grade: " << grade << endl;
}
};
int main() {
// Create a Student object
Student student1("Alice", 85); // Name: Alice, Grade: 85
return 0;
}
In this example, the private keyword hides name and grade (data hiding), whereas public
methods like getName(), getGrade(), and setGrade() control access to these
private members, demonstrating encapsulation. The setGrade() method even includes
validation logic, further illustrating the control encapsulation provides.
Activity 12.5
How can encapsulation improve modularity and maintainability in a C++ program?
336
12.6. Abstraction
Abstraction refers to the concept of hiding unnecessary details and showing only
the essential features of an object or a system. It allows developers to focus on what
an object does instead of how it does it.
337
private:
string name;
int grades[3]; // private data, hidden from the user
// Private helper method (implementation detail, hidden)
double calculateSumOfGrades() const {
int sum = 0;
for (int i = 0; i < 3; ++i) {
sum += grades[i];
}
return static_cast<double>(sum);
}
public:
// Constructor
Student(string n, int g1, int g2, int g3) : name(n) {
grades[0] = g1;
grades[1] = g2;
grades[2] = g3;
}
// Public method to calculate average grade (interface)
double calculateAverageGrade() const {
return calculateSumOfGrades() / 3.0; // User doesn't need to
// know how sum is calculated
}
int main() {
Student student1("Jozy", 85, 90, 92);
[Link](); // Output: Name: Jozy, Average Grade: 89
338
In this example, the Student class encapsulates the student’s name and grades. The
internal details of how the average grade is calculated (e.g., the grades array and the
calculateSumOfGrades helper method) are hidden. The user only interacts with the
public methods calculateAverageGrade() and displayInfo(), focusing on what
the student object can do, not how it manages its grades internally.
[Link]. Using Abstract Classes and Pure Virtual Functions (Higher Level
Abstraction)
A higher level of abstraction can be achieved using abstract classes. As discussed in
the polymorphism section, an abstract class contains at least one pure virtual function
(a function that has no implementation in the base class, denoted by = 0).
• Enforcing an Interface: Abstract classes define a common interface that all their
concrete derived classes must adhere to. They specify what derived classes must
do, but not how they should do it.
339
void displayFinalGrade() const {
cout << "Name: " << name << ", Final Grade: "
<< calculateFinalGrade() << endl;
}
// Virtual destructor is important for proper cleanup in polymorphic
// hierarchies
virtual ~StudentBase() = default;
};
// Derived class for regular students (e.g., based on assignments and exams)
class RegularStudent : public StudentBase {
private:
int grades[3];
public:
RegularStudent(string n, int g1, int g2, int g3) : StudentBase(n)
{
grades[0] = g1;
grades[1] = g2;
grades[2] = g3;
}
340
int main() {
RegularStudent regularStudent("Chisomo", 78, 82, 85);
ProjectStudent projectStudent("Mphatso", 90);
// Polymorphic usage:
StudentBase* s1 = ®ularStudent;
StudentBase* s2 = &projectStudent;
return 0;
}
This example creates a base abstract class StudentBase that has a pure virtual
function calculateFinalGrade(). This forces all derived classes (like
RegularStudent and ProjectStudent) to implement their own specific logic for
calculating the final grade. The displayFinalGrade() method in the base class
provides a common interface, abstracting away the different grading schemes. The user
of these classes only needs to know that a student has a calculateFinalGrade()
method, not the specific details of how that grade is derived for each student type.
341
Role of Header Files in Abstraction
A header file (.h) contains:
• Class declarations
• Function prototypes
• Constants
Header files hide the implementation details, which are written in .cpp files, and
provide only interfaces to the programmer.
Benefits:
• Promotes code reuse
• Simplifies program maintenance
• Supports modular programming
• Provides information hiding (abstraction)
#include <string>
using namespace std;
class Student {
private:
int id;
string name;
public:
Student(int i, string n); // Constructor prototype
void display(); // Display function prototype
};
class Grade {
private:
float marks;
public:
Grade(float m); // Constructor prototype
char getLetterGrade(); // Function prototype
};
#endif
342
• This file hides all implementation details. Users only see class names, functions,
and data types.
#include <iostream>
#include "student.h"
using namespace std;
void Student::display() {
cout << "ID: " << id << ", Name: " << name << endl;
}
char Grade::getLetterGrade() {
if (marks >= 80) return 'A';
else if (marks >= 60) return 'B';
else if (marks >= 50) return 'C';
else return 'F';
}
#include <iostream>
#include "student.h"
using namespace std;
int main() {
Student s1(101, "Alice");
Grade g1(85);
[Link]();
cout << "Letter Grade: " << [Link]() << endl;
return 0;
}
343
• Header file: Only declarations (abstract interface)
• CPP file: Actual implementation hidden
• Main file: Uses the interface without knowing implementation details
Activity 12.6
Explain the role of header files in abstraction.
344
12.7.1. Key Aspects of Message Passing in C++
1. Object Communication through Method Invocations: The primary way objects
communicate is by one object invoking a method of another object. This method
call is considered the "message" being sent.
2. Message:
o The message is simply the method call that an object sends to another.
o The parameters of the method can be considered the content or payload
of the message, providing necessary data for the receiving object to perform
its action.
3. Interaction:
o Objects interact by sending messages to each other.
o The receiver object responds by executing its corresponding method,
processing the message, and potentially returning a result.
345
12.7.3. Benefits of Message Passing
1. Modularity: Objects operate independently and communicate only, when
necessary, through well-defined interfaces. This promotes modularity, making it
easier to develop, test, and understand individual components of a system.
2. Abstraction: The details of how operations are implemented within an object are
hidden from the sender of the message. The sender only needs to know what
message to send and what parameters to provide, not the internal workings of the
receiver.
3. Reusability: Objects can be reused and extended in different parts of the system.
Since objects interact through messages, they are loosely coupled, making it
easier to integrate them into new contexts or extend their functionalities.
class Student {
private:
string name;
int grade;
public:
Student(string n) : name(n), grade(0) {}
346
class Teacher {
public:
// Message passing: Teacher updates the student's grade
// The Teacher object sends a 'setGrade' message to the Student object.
void updateGrade(Student &student, int newGrade) {
cout << "Teacher is updating grade for " << [Link]()
<< "..." << endl;
// Sending message to Student object: invoking its setGrade method
[Link](newGrade);
}
};
int main() {
// Creating a student object
Student student1("John");
[Link](); // Initial grade: 0
return 0;
}
In this example, the Teacher object sends a "message" to the Student object
(student1) by invoking its setGrade() method. The setGrade() method then
performs the action (updating the grade) and provides feedback. This demonstrates how
one object (Teacher) interacts with another object (Student) to perform some action
(update grade) through a controlled method call, embodying the concept of message
passing.
Activity 12.7
a. Explain how message passing supports the concept of encapsulation in C++.
b. How are member function calls in C++ considered a form of message
passing?
347
12.8 Interfaces
An interface in C++ defines what operations a class must perform, without defining
how they are performed. C++ does not have a separate interface keyword.
Instead, interfaces are created using:
• Abstract classes
• Pure virtual functions
Interfaces support: Abstraction, Polymorphism and Loose coupling
Syntax
virtual returnType functionName() = 0;
Example
class Student {
public:
virtual float calculateGrade() = 0; // Pure virtual function
};
• The class Student does not define how grades are calculated. Every student
type must implement its own grading logic.
• Has no implementation in the base class. Forces derived classes to override
the function. Used to define interfaces
Characteristics
• Cannot be used to create objects
• Can have:
o Pure virtual functions
o Normal member functions
o Data members
• Used as a base class
348
Abstract Class Example
class Student {
protected:
int id;
string name;
public:
Student(int i, string n) {
id = i;
name = n;
}
public:
ExamStudent(int i, string n, float m) : Student(i, n) {
examMarks = m;
}
float calculateGrade() {
return examMarks;
}
};
public:
CourseworkStudent(int i, string n, float m) : Student(i, n) {
courseworkMarks = m;
}
float calculateGrade() {
return courseworkMarks * 0.5;
}
};
349
Interfaces
An interface in C++ is an abstract class that:
• Contains only pure virtual functions
• Has no data members (recommended)
• Defines a contract that derived classes must follow i.e. Defines a grading
contract that all student types must follow
public:
StudentGrade(float m) {
marks = m;
}
float getFinalGrade() {
return marks;
}
char getLetterGrade() {
if (marks >= 80) return 'A';
else if (marks >= 60) return 'B';
else if (marks >= 50) return 'C';
else return 'F';
}
};
350
Interface Pointer Example
int main() {
GradeInterface* g;
StudentGrade s(75);
g = &s;
cout << "Final Grade: " << g->getFinalGrade() << endl;
cout << "Letter Grade: " << g->getLetterGrade() << endl;
return 0;
}
2. Enables Polymorphism
• Same interface, different behavior i.e. Same interface, different grading methods
GradeInterface* g;
351
12.9. Modeling Real-World Systems with OOP
In the previous lessons, we introduced the fundamental concepts of Object-Oriented
Programming (OOP), including classes, objects, encapsulation, inheritance, and
polymorphism. Now, we will bring these concepts together by constructing a practical C++
program that models a basic banking system. This example will serve as a hands-on
demonstration of how OOP principles are applied to design and implement robust and
flexible software solutions that mirror real-world entities and their interactions.
Our banking system will feature different types of bank accounts, such as a general
BankAccount and a more specialized SavingsAccount. We will see how properties
and behaviors are shared and extended across these account types, and how the system
can interact with them in a unified manner.
#include <iostream>
#include <string>
using namespace std;
public:
// Constructor
BankAccount(const string& holder, double initialBalance)
: accountHolder(holder), balance(initialBalance) {}
352
virtual void displayAccountInfo() const {
cout << "Account Holder: " << accountHolder
<< "\nBalance: MKW" << balance << endl;
}
public:
// Constructor with interest rate
SavingsAccount(const string& holder, double initialBalance, double
rate): BankAccount(holder, initialBalance), interestRate(rate) {}
353
int main() {
// Create objects of base and derived classes
BankAccount account1("Mercy Banda", 1000.0);
SavingsAccount account2("Joseph Phiri", 2000.0, 5.0);
// 5% interest
// Perform transactions
[Link](500.0);
[Link](200.0);
cout << "--------------------------" << endl;
return 0;
}
2. Inheritance
• Mechanism by which one class (child/derived) inherits properties and behaviors
from another class (parent/base).
• How it's used:
354
o SavingsAccount inherits from BankAccount using public
inheritance.
o It reuses code from the base class and adds new features (interest rate).
3. Polymorphism
• The ability to process objects differently depending on their data type or class.
• Types:
o Compile-time (Function Overloading) – not shown here.
o Runtime (Virtual Functions) – demonstrated in this program.
• How it's used:
o Functions like displayAccountInfo(), deposit(), and
withdraw() are marked virtual in the base class.
o They are overridden in the derived class to change behavior.
o This allows calling the correct function depending on the object type
(dynamic dispatch).
virtual void displayAccountInfo() const;
4. Abstraction
• Hiding complex details and showing only the essential features.
355
BankAccount account1("Mercy Banda", 1000.0);
SavingsAccount account2("Joseph Phiri", 2000.0, 5.0);
Activity 6.8
Modify the example as follows:
a. Add a CurrentAccount class that charges transaction fees.
b. Implement interest calculation monthly instead of per deposit.
c. Add user input in main() for interactive banking.
d. Add a transfer() function to move money between accounts.
Unit summary
In this Unit, you have covered the following main points:
• Classes and objects form the foundation of object-oriented programming,
defining the structure and instances within a program.
• Encapsulation is a key concept, ensuring the protection of data and methods
within a class and controlling access to them through access specifiers.
• Inheritance allows for the creation of new classes based on existing ones,
inheriting properties and behaviors and promoting code reuse.
• Polymorphism, achieved through function overloading and overriding, provides a
unified interface for multiple types, enhancing flexibility and code elegance.
• Abstraction involves creating abstract classes with pure virtual functions, allowing
for the definition of generalized structures and fostering modularity.
• Constructors and destructors are special member functions handling the
initialization and cleanup of objects, respectively.
• Pointers and dynamic memory allocation contribute to the flexibility of
polymorphism by allowing the creation and manipulation of objects during
runtime.
• Operator overloading permits the redefinition of operators for user-defined types,
enhancing the expressiveness of code.
356
• Static members are shared among all instances of a class, remaining constant
irrespective of object creation.
• Friend functions provide external functions with access to private and protected
members of a class, fostering a balance between encapsulation and flexibility.
357
UNIT
13 UNIT 13: TEMPLATES
Introduction
In the world of software development, writing efficient, flexible, and reusable code is
paramount. Often, we encounter situations where the same logic needs to be applied to
different data types. For example, you might need a function to swap two integers, and
then later, a function to swap two floating-point numbers, or even two strings. Without a
mechanism to generalize this logic, you would end up writing almost identical code for
each data type, leading to redundancy and increased maintenance effort.
This is where templates in C++ come into play. Templates are a powerful feature that
supports generic programming. Generic programming is a paradigm that allows the
development of reusable software components, such as functions, classes, and
algorithms, that can work with different data types without needing to rewrite the same
logic multiple times.
Using templates, we can write a single function or class definition that acts as a blueprint.
This blueprint can then be used to create specific versions of the function or class for
various data types as needed. This significantly increases code reusability and
efficiency by eliminating redundant code and promoting a more abstract approach to
problem-solving.
Unit outcomes
By the end of this unit, you must be able to:
• Understand the concept of generic programming.
• Create and use function and class templates.
• Work with multiple template parameters.
• Apply template specialization for specific data types.
• Explain the basics of the Standard Template Library (STL).
358
Key terms
Ensure that you understand the following key terms or phrases used in this unit:
Templates, Generic Programming, Function Templates, Class Templates, Placeholder
Type, Template Instantiation, Template Specialization, Standard Template Library,
Containers, Iterators, Algorithms, Functors.
Think of a template as a recipe where one of the ingredients is a placeholder. When you
want to bake, you specify the actual ingredient (e.g., "flour," "sugar"), and the recipe then
guides you to bake a specific type of cake. Similarly, with templates, you define a generic
structure, and when you use it, you specify the actual data type, and the compiler
generates the specific code for that type.
Instead of writing separate, overloaded functions for each data type (e.g., swap(int&,
int&), swap(float&, float&), swap(string&, string&)), a function
template allows you to write one generic swap function that works for any type.
359
The template declaration uses a placeholder type, commonly represented by T (or any
other identifier), which gets replaced by the actual data type when the function is called.
The compiler then generates a specific version of the function (an "instantiation") for
that particular data type.
header.
o template: Keyword indicating a template definition.
o <class T> or <typename T>: Declares T as a template type
parameter. Both class and typename keywords are interchangeable in this
context when declaring a type parameter. typename is often preferred for
clarity, as T can represent any type, not just a class.
o T: The placeholder type that will be replaced by an actual data type (e.g.,
int, float, string, or a custom class) when the template is used.
360
string temp = a;
a = b;
b = temp;
}
Notice that the logic of these two functions is identical; only the data type differs. This is
a perfect scenario for a function template.
This single swap function template can now be used to swap any two variables of the
same type (as long as that type supports assignment and copy construction), whether
they are int, float, double, char, string, or even custom class objects.
Such a template function is readily available in the Standard Template Library (STL) that
comes with standard C++ compilers. The swap function is declared in the <algorithm>
header file.
361
#include <iostream>
#include <string>
using namespace std;
template<class T>
void swapValues(T &a, T &b) {
T temp = a;
a = b;
b = temp;
}
int main() {
// Swapping characters
char ch1, ch2;
cout << "Enter two characters: ";
cin >> ch1 >> ch2;
swapValues(ch1, ch2);
cout << "Swapped characters: " << ch1 << " " << ch2 << endl;
// Swapping integers
int a, b;
cout << "Enter two integers: ";
cin >> a >> b;
swapValues(a, b);
cout << "Swapped integers: " << a << " " << b << endl;
// Swapping floats
float p, q;
cout << "Enter two floats: ";
cin >> p >> q;
swapValues(p, q);
cout << "Swapped floats: " << p << " " << q << endl;
// Swapping strings
string s1, s2;
cout << "Enter two strings: ";
cin >> s1 >> s2; // Note: cin reads until whitespace
swapValues(s1, s2);
cout << "Swapped strings: " << s1 << " " << s2 << endl;
return 0;
}
In this example, the same swapValues function template is used to swap characters,
integers, floats, and strings without needing separate, type-specific functions for
each data type. The compiler automatically deduces the type T based on the arguments
passed during the function call and generates the appropriate code.
362
[Link]. Function Templates – Example II: findMax
Another common scenario for templates is finding the maximum (or minimum) of two
values of any type.
#include <iostream>
using namespace std;
int main() {
// Finding maximum of two integers
int grade1 = 85, grade2 = 90;
cout << "Maximum (int): " << findMax(grade1, grade2) <<endl;
This findMax function template efficiently returns the maximum of two grades,
regardless of whether they are int, float, double, or even char, as long as the >
operator is defined for that type.
363
13.1.2. Overloading of Function Templates
Just like regular functions, you can also overload function templates. This means you
can have multiple function templates with the same name, but they must differ in their
parameter lists (number or types of parameters). The compiler will then use overload
resolution rules to determine which template (or non-template function, if available) to
instantiate and call.
int main() {
// Calls the first template: print(T a)
print(1); // T is int, prints 1
print(3.4); // T is double, prints 3.4
print("hello"); // T is const char*, prints "hello"
return 0;
}
364
In this example:
• print(1) and print(3.4) call the first template print(T a).
• print(455,3) and print("world",2) call the second template print(T a,
int n).
The compiler correctly distinguishes between the two templates based on the number of
arguments provided in the function call.
Syntax:
template <class T1, class T2, ..., class Tn> // or using typename
return_type function_name(T1 arg1, T2 arg2, ..., Tn argn) {
// function body
}
return 0;
}
365
In this example, the sum function template takes two different type parameters, T and U.
This allows it to find the sum of two numbers even if they are of different types. The
static_cast<T>(b) ensures that the operation is performed with type T and the result
is of type T.
The syntax for class templates is similar to that of function templates, but the template
header precedes the class definition.
366
• ClassName<T>: When referring to the class template itself (e.g., in member
function definitions outside the class), you must include the template parameter
list.
public:
// Constructor to initialize the grade
Student(T g) : grade(g) {}
// Member function to display the grade
void displayGrade() {
cout << "Student's Grade: " << grade << endl;
}
};
int main() {
// Create Student objects with different grade types
Student<int> student1(85); // T is int
Student<float> student2(89.5f); // T is float
Student<double> student3(90.75); // T is double
Student<char> student4('A'); // T is char
// Display grades
[Link](); // Output: Student's Grade: 85
[Link](); // Output: Student's Grade: 89.5
[Link](); // Output: Student's Grade: 90.75
[Link](); // Output: Student's Grade: A
return 0;
}
367
In this example, the Student class template allows us to create Student objects that can
hold grades of various numeric types (int, float, double) or even a character type
(char), all using the same class definition.
When the compiler encounters a template instantiation request for a specialized type, it
will use the specialized version instead of the generic template.
368
void displayGrade() {
cout << "Student's Grade: " << grade << endl;
}
};
return 0;
}
369
Syntax:
template <typename T1, typename T2, ..., typename Tn>
class ClassName {
T1 data1;
T2 data2;
// ...
public:
ClassName(T1 arg1, T2 arg2) : data1(arg1), data2(arg2) {}
void display();
};
[Link]. Templates with Multiple Parameters - Example: Student Class with Name
and Grade
Consider a Student class that needs to store both the student's name (which is always
a string) and their grade (which could be an int, float, or double).
#include <iostream>
#include <string>
using namespace std;
int main() {
// Student with string name and int grade
Student<string, int> student1("Alice", 85);
[Link](); // Output: Student: Alice, Grade: 85
// Student with string name and float grade
Student<string, float> student2("Bob", 89.5f);
[Link](); // Output: Student: Bob, Grade: 89.5
// Student with string name and double grade
Student<string, double> student3("Charlie", 92.33);
[Link]();// Output: Student: Charlie, Grade: 92.33
return 0;
}
370
In this example, the Student class template uses T1 for the name and T2 for the grade.
This allows us to create Student objects where the name is always a string, but the
grade can be of any specified numeric type.
#include <iostream>
#include <string>
Using namespace std;
void displayInfo() {
cout << "Student: " << name << ", Grade: " << grade << endl;
}
};
371
int main() {
Student student("Charlie",87.0f); // Create a regular Student object
return 0;
}
In this example, the Student class is a concrete class. However, its compareGrades
member function is a template, allowing it to compare grades of any type T. This
demonstrates flexibility by making only specific functionalities generic within a class.
372
Basic Template Without Argument Deduction
#include <iostream>
using namespace std;
int main() {
cout << add<int>(5, 10); // Explicit type
return 0;
}
Example
#include <iostream>
using namespace std;
int main() {
cout << add(5, 10); // Compiler deduces T as int
cout << add(2.5, 3.5); // Compiler deduces T as double
return 0;
}
373
Argument Deduction with Different Data Types
• The compiler automatically determines the type of T.
template <class T>
void display(T value) {
cout << value << endl;
}
int main() {
display(100); // int
display(3.14); // double
display('A'); // char
display("Hello"); // const char*
return 0;
}
int main() {
cout << multiply(3, 4); // T = int
cout << multiply(2.5, 4.0); // T = double
return 0;
}
int main() {
cout << add(5, 2.5); // Error: int and double
return 0;
}
374
Solutions:
1. Explicit Template Argument
cout << add<double>(5, 2.5);
int main() {
int a = 10;
show(a); // T deduced as int
return 0;
}
int main() {
int a = 5;
const int b = 10;
display(a); // T = int
display(b); // T = int
return 0;
}
375
Argument Deduction in Class Templates (Constructor Deduction – C++17)
• Available from C++17 onwards
#include <iostream>
using namespace std;
int main() {
Box b(100); // T deduced as int
Box c(3.14); // T deduced as double
return 0;
}
376
ii. Type Safety:
o Unlike C-style generic programming (e.g., using void* pointers), templates
are type-safe. The compiler enforces type correctness when instantiating
templates.
o This means that type mismatches are caught at compile time, reducing
runtime errors and making your code more robust and reliable.
iii. Flexibility:
o Templates can be used for a wide variety of tasks, including implementing
complex data structures (like linked lists, trees, hash tables) and algorithms
(like sorting, searching, mathematical operations) that can operate on any
data type.
o This flexibility allows developers to build highly adaptable and versatile
software components.
Activity 13.1
How are templates instantiated during compilation in C++?
377
13.2.1. Components of STL
The STL is conceptually divided into three main components that work together:
1. Containers: Objects that store collections of data.
2. Iterators: Objects that point to elements inside containers, acting as a bridge
between containers and algorithms.
3. Algorithms: Functions that perform operations on elements within containers,
typically using iterators.
[Link]. Containers
Containers are objects that store collections of data. The STL provides various types of
containers, each with different characteristics and performance trade-offs, classified into
three main categories:
i. Sequence Containers:
These containers store data in a linear fashion, where elements are arranged in a
specific order. They provide sequential access to elements.
• vector: A dynamic array that can grow or shrink in size. It provides efficient
random access to elements and is generally the most commonly used container.
o Example: vector<int> numbers = {1, 2, 3};
• list: A doubly-linked list. It provides efficient insertion and deletion anywhere in the
list (constant time) but does not support random access (linear time to access an
element).
o Example: list<std::string> names = {"Alice", "Bob"};
• array (C++11 onwards): A fixed-size array that provides a safer and more
convenient interface than C-style arrays. It's a compile-time fixed-size container.
o Example: array<int, 5> arr = {1, 2, 3, 4, 5};
378
• forward_list (C++11 onwards): A singly-linked list, more memory-efficient than
list but only allows forward traversal.
o Example: forward_list<double> values = {1.1, 2.2};
• set: Stores unique elements in sorted order. Only the keys are stored, and they
serve as both keys and values.
o Example: set<int> unique_numbers = {10, 20, 30};
379
iii. Container Adaptors:
These are not true containers but rather provide a different interface to underlying
sequence containers (usually deque or list). They restrict the operations available to
enforce specific data structures.
• stack: A last-in, first-out (LIFO) data structure. Elements are pushed onto the
top and popped from the top.
o Example: stack<int> s; [Link](10); [Link]();
• queue: A first-in, first-out (FIFO) data structure. Elements are pushed at the
back and popped from the front.
o Example: queue<string> q; [Link]("task1"); [Link]();
[Link]. Iterators
Iterators are objects that act like pointers, allowing you to point to elements inside
containers and traverse through them. They provide a generalized way to access
elements of any container type, abstracting away the underlying storage mechanism.
• They act as a bridge between containers and algorithms, enabling algorithms to
work uniformly across different container types.
• Iterators provide a consistent interface for traversing and accessing elements.
There are five main categories of iterators, each with different capabilities:
i. Input Iterators: Can be read from (*it) and moved forward (++it), but not
modified. They are used for single-pass input operations.
ii. Output Iterators: Can be written to (*it = value) and moved forward (++it),
but not read. They are used for single-pass output operations.
380
iii. Forward Iterators: Can move forward (++it), and can be read from and written
to multiple times. They combine the capabilities of input and output iterators.
iv. Bidirectional Iterators: Can move forward (++it) and backward (--it), and
can be read from and written to. list iterators are bidirectional.
v. Random Access Iterators: Provide all the capabilities of bidirectional iterators,
plus the ability to move to any element in constant time using arithmetic
operations (e.g., it + n, it - n). vector and deque iterators are random
access iterators.
int main() {
vector<int> numbers = {10, 20, 30, 40, 50};
return 0;
}
381
[Link]. Algorithms
Algorithms are functions that perform a wide range of operations on elements within
containers. They are generic, meaning they work with different container types as long
as the iterators provided meet the algorithm's requirements.
• STL provides a rich set of algorithms for common operations like sorting,
searching, manipulating elements, and numerical operations.
• Algorithms work with containers primarily through iterators, which define the
range of elements the algorithm should operate on.
• find: Searches for a given value in a specified range and returns an iterator to the
first occurrence if found, or end() if not found.
o Example: auto it = find([Link](), [Link](), 30);
382
Example of using an algorithm (sort):
#include <iostream>
#include <vector>
#include <algorithm> // Required for sort
using namespace std;
int main() {
vector<int> numbers = {50, 20, 40, 10, 30};
return 0;
}
383
ii. Lambda Functions (C++11 onwards):
o Lambda functions are anonymous functions that can be defined in-place,
often used for short, localized operations.
o They are frequently used in STL algorithms as compact alternatives to
functors or separate functions, providing custom behavior directly where
needed without the overhead of defining a full class or named function.
The STL is an indispensable part of modern C++ programming, essential for writing
efficient, robust, and reusable code. By mastering containers, iterators, and algorithms,
you can handle various programming tasks efficiently and effectively, leveraging a vast
library of pre-built, high-performance components.
Activity 13.2
How does STL support generic programming in C++?
384
2. C++ for Machine Learning and AI:
o C++ is a crucial language for the backend implementations of many popular
Machine Learning (ML) and Artificial Intelligence (AI) frameworks.
Frameworks like TensorFlow and PyTorch use C++ extensively for their
performance-critical core operations (e.g., tensor computations, neural
network inference).
o Due to its speed and fine-grained control over memory, C++ is often chosen
for developing high-performance ML libraries, custom AI models, and deep
learning inference engines.
o C++ is also being used in specialized deep learning libraries like dlib for tasks
such as facial recognition, object detection, and other AI-based applications
where performance is critical.
385
5. C++ for Game Development and Graphics Programming:
o C++ has long been the industry standard for game development. Major game
engines like Unreal Engine and Unity (for its core) use C++ extensively for
their performance-critical rendering, physics, and game logic.
o The demand for real-time rendering and advanced 3D graphics
programming continues to make C++ a key language in the gaming industry.
o Trends like ray tracing (for realistic lighting) and integration with modern
graphics APIs like Vulkan and DirectX 12 with C++ are major areas of
innovation in high-performance graphics programming.
386
standard in large-scale software development, reducing common pitfalls like
memory leaks.
These technologies are continually expanding the relevance and utility of C++ in modern
software ecosystems, especially in demanding, high-performance applications across
domains like Artificial Intelligence (AI), Internet of Things (IoT), blockchain, and gaming.
Activity 13.3
Explain the role of C++ in the development of high-performance applications such
as game engines or trading systems.
387
Unit summary
In this Unit, you have covered the following main points:
• Templates support generic programming, letting code work with different data
types using the same logic.
• C++ provides two main types of templates: function templates and class
templates.
• Function templates allow one function to handle multiple data types and can be
overloaded.
• Class templates let you create generic classes, useful for building data
structures.
• Template specialization allows custom behavior for specific data types.
• Templates improve code reusability, type safety, and flexibility.
• The Standard Template Library (STL) uses templates to offer ready-made
containers, iterators, and algorithms.
You’ve learned how templates support generic programming, allowing code to handle
different data types with the same logic. In the next unit, we’ll explore file processing in
C++ and learn how to read from and write to files.
388
UNIT
14 UNIT 14: FILE HANDLING
Introduction
The prime role of computers is problem solving and data processing. In any computer
application, the basic entity is data. Data can be either simple or it may have multiple
attributes (fields). One needs to select the appropriate data structure based on the nature
of the application and data. So far with your programs, the data entered is gone when you
run the program next time. In this unit you will learn how to save the entered data or
calculated during one run so that you can continue where you stopped last time. This will
be done by saving the data on disk in files. This unit also discusses basic concepts of file
management and how to read and write to files.
Unit outcomes
By the end of this unit, you must be able to:
• Define ‘file’
• Explore schemes of file organization
• Discuss factors that affect file organization
• Examine factors involved in selecting file organization
• Learn what a stream is and examine input and output streams
• Become familiar with file opening modes
• Explore how to read data from the standard input device
• Learn how to write data to the standard output device
• Learn how to use file predefined functions in a program
Key terms
Ensure that you understand the following key terms or phrases used in this unit: file,
binary file, sequential file, random access file, stream, ifstream, ofstream, fstream,
instream, outstream, infile, outfile and end of file (EOF).
389
14.1. File
File is the container of content in a computer. A file is a collection of records where each
record consists of one or more fields. A folder is an example of file. A folder contains files.
Mostly a file is referred to that container which do not house other files. But houses actual
data. Generally, file have names and usually their names end with an extension which is
separated by a dot (.) such as [Link]. Other file extensions are: .txt, .docx,
.doc, .csv, .dat, .mp3, etc. Information can be saved to files and later retrieved.
Files are crucial to the operation of many real-world programs, Database Management
Systems, Spreadsheets, etc. use files.
C++ program can read content from the file and write the content to the file. Writing
program’s content to the file ensures that the content is available during the next run of
program. This is so because the content is permanently saved on the hard disk drive.
Schemes decide the way in which records are stored and accessed in a file: Various
schemes for file organization are available:
• Sequential file
• Direct or random-access file
• Indexed sequential file
• Multi-indexed file
390
[Link]. Sequential file
In sequential file, records are stored in the sequential order of their entry. This is the
simplest kind of data organization. In sequential files, the records are stored in ascending
or descending order of keys. When the records are not arranged in an organized fashion,
they are stored as per their sequence of arrival; this organization is known as serial
organization.
391
2. Type of query: - Depending on the type of query, file organization will be affected.
In a simple query, values for the single key are specified. In a range query, range
for the key is specified.
3. Number of keys: - The file may or may not have a key. Each key may have one
or more fields. Accessing the desired record is made easy with the keys.
A file should be organized in such a way that the records are always available for
processing with no delay. This should be done in line with the activity and volatility of the
information.
Activity 14.1
State the advantages and disadvantages of sequential files.
392
14.2. File Streams
File handling is an important part of programming. Most of the applications have their own
features to save data to the secondary storage and read from it again. File I/O classes in
C++ simplify such file read/write operations. The I/O system of C++ contains a set of
classes that define the file handling methods. They are ifstream, ofstream, and
fstream. These classes are included in the ‘fstream.h’ header file.
• ifstream: - This class provides input operations.
• ofstream: - This class provides output operations.
• fstream: - This class provides both input and output operations.
Streams
When files are processed in C++, the communication goes between hard disk file and
program via a stream. A file which the program is reading from is called infile. A file which
the program is writing to is called outfile.
The data from infile goes to the program via an intermediary store called instream.
Instream works as a buffer between the hard disk and the program, where data is queued
to be read to the program.
The data from the program goes to the outfile via an intermediary store called
outstream. Outstream works as a buffer between the hard disk and the program, where
data is queued to be read to the hard disk (outfile).
393
Figure 14.1: File streams (Adapted from Backman, 2013, p. 154)
394
14.2.2. Opening a File
Creating a file stream object to manage the stream using the ofstream, ifstream, or
fstream. The open()function accepts a second argument which specifies the mode in
which the file should be opened.
Ofstream outFile;
[Link](“[Link]”, ios::app);
If more than one mode is passed, the modes are separated by a pipe (OR operator, |)
fstream inOutFile(“[Link]”, ios::in|ios::out);
Examples
1. To create an object ofile and open a file with name [Link] for output
only
ofstream ofile(“[Link]”);
2. To create an object ifile and open a file with name [Link] for input only
ifstream ifile(“[Link]”);
3. To create an object file1 and open a file with name [Link] for input
and output.
fstream file1(“[Link]”);
395
2. ios::ate
Open a file for output and move the read/write control to the end of the file.
3. ios::binary
Binary mode. When a file is opened in binary mode, information is written to or
read from it in pure binary format.
4. ios::in
Input mode. Information will be read from the file. If the file does not exist, it will not
be created and the open function will fail.
5. ios::out
Output mode. Information will be written to the file. By default, the file’s contents
will be deleted if it already exists.
6. ios::trunc
If the file already exists, its contents will be deleted (truncated). This is the default
mode used by ios::out
Activity 14.2
What file operation must be performed before information can be written to or read
from a file?
396
14.3. Reading from a File and Writing to a File
To work with files in a program you must include header, fstream.h.
To read from a file, you must first instantiate a file stream object of type ifstream and
use it to open a file.
Example:
ifstream infile
[Link](“[Link]”); /* [Link] is in current
directory (same directory with the program file) */
OR simply as:
ifstream variable(filepath)
Example:
ifstream infile(“[Link]”); /*[Link] is in
current directory (same directory with the program file)*/
Then the data can be read from file in similar way the text is input using cin. But instead
of cin object, here you use file stream object instantiated i.e. infile
infile>>line; //line is variable for reading
The code below will only read characters until a space is encountered
infile>>line; // delimited by space
To fetch the whole line per read from the file stream, the getline() function is used.
[Link](line,81); //delimited by ‘\n’ (new line)
397
Note that ifstream attempts to open the file. Sometimes the file might not exist. So, it
is a good practice to check whether the ifstream succeeded to open the file (file exists)
or not (file does not exist). This check guarantees that the file is open before you start
reading it. Use is_open() function to do this checking.
ifstream infile(“[Link]”);
if(! Infile.is_open())//if the opening of the file failed
{
cout << “Could not open the file”;
}
When you are reading the whole content from the file, you can check whether you have
reached the end of file (EOF) to stop reading. Use eof() function to do this checking as
shown below:
ifstream infile(“[Link]”);
if(! [Link]()) // if not at the end of the file
{
//code to read the line of the file
}
Activity 14.3a
Describe the difference between reading a file with the >> operator and with the
getline member function.
398
14.3.3. Writing to a File
To write to a file, outstream must be declared first and attached to a disk file before
using that outstream. To declare outstream use ofstream. Ofstream is for “output file
stream” as shown below:
ofstream variable(filename);
To write to a file, you first instantiate a file stream object of type ofstream and use it to
open a file:
ofstream outfile
[Link](“[Link]”);
OR simply as:
ofstream outfile(“[Link]”);
Then the data can be written to file in similar way the text is displayed on screen using
cout. But instead of cout object, here we use file stream object instantiated i.e.
outfile.
Outfile<<Products;
Use is_open() function to check if the file you want to write to was successfully open:
ofstream outfile(“[Link]”);
if(! Outfile.is_open()) // if the opening of the file failed
{
cout << “Could not open the file”;
return 0; //terminate the program
}
Example: Writing to a stream (file). This program overwrites existing products each time
it is run
#include<iostream>
#include<fstream>
using namespace std;
int main()
399
{
char products[30] = “ “;
ofstream outfile(“[Link]”);
cout << endl << “Enter product: (To Exit Press
Enter)”<<endl;
[Link](products,29);
while(products[0]!=’\0’)
{
outfile<<products<<endl;
cout<<endl<<”Enter product: “;
[Link](products,29);
}
[Link]();
return 0;
}
Example: Writing to the end of file. This program appends a product to the existing
products each time it is run.
#include<iostream>
#include<fstream>
using namespace std;
int main()
{
char products[30] = “ “;
ofstream outfile(“[Link]”,ios::app);
cout << endl << “Enter product: (To Exit Press
Enter)”<<endl;
[Link](products,29);
while(products[0]!=’\0’)
{
outfile<<products<<endl;
cout<<endl<<”Enter product: “;
[Link](products,29);
}
[Link]();
return 0;
}
400
Example: Reading from a stream (file). This program will read the contents of a file
[Link] which was created in the previous example (Make sure you entered
the products in [Link] file).
#include<iostream>
#include<fstream>
using namespace std;
int main()
{
char products[30] = “ “;
ifstream infile(“[Link]”);
if (!infile.is_open() )
{
cout << “Could not open file!”;
}
//read a line by line
while(![Link]())
{
[Link](products,29);
cout << products <<endl;
}
[Link]();
return 0;
}
401
Example: Copying a file using rdbuf() function
#include<iostream>
#include<fstream>
#include<cstdio>
using namespace std;
int main()
{
char Newname[12];
cout<<”Enter New File Name: “;
cin>>Newname;
ifstream infile(“[Link]”);
ofstream outfile(Newname);
if(!outfile)
{
cout << “The File could not be created”;
}
else
{
outfile << [Link]();
}
[Link]();
[Link]();
return 0;
}
Activity 14.3b:
Describe the purpose of the put member function.
402
14.4. Binary Files
Binary files play a crucial role in storing and managing data efficiently in the digital world.
In C++, working with binary files involves using the fstream library to handle input and
output operations. These files differ from text files in that they store data in a binary format,
providing a direct representation of the underlying data structures.
Binary file is any file which is not text file. Binary files have their content constructed with
zeros and ones. Text files are constructed by using binary codes such as ASCII codes.
People find it natural to work with numbers in their string representation. Computer
hardware is better adapted to processing numbers in their binary form. Examples of
binary files are: Executables and Images such as JPEG or PNG.
Take a moment to reflect on this illustration: In what manner is the value 1297 stored in
a file?
ofstream outfile(“[Link]”);
short x = 1297; //occupies 2 bytes in memory
outfile<<x;
From the illustration above, the last statement writes the content of x (1297) into the file.
However, this number is written in a file as a string of 4 characters: ‘1’, ‘2’, ‘9’, and ‘7’,
hence occupying 4 bytes. If 1297 is stored to the file in the same representation as it is
in memory, we can save 2 bytes as only 2 bytes are used.
Example:
403
14.4.2. Writing to Binary Files
ofstream has a write () function that can be used to write to binary file. Employ the
write() method to store binary data. Pay attention to data type and size consistency.
Syntax:
[Link](reinterpret_cast<const char*>(&variable),
sizeof(variable));
write(char *address_of_buffer, int number_of_bytes);
Example:
double dl = 45.9;
double dArray[3] = { 12.3, 45.8, 19.0 };
ofstream outfile(“[Link]”, ios::binary);
[Link](reinterpret_cast<char *>(&dl), sizeof(d1));
[Link](reinterpret_cast<char *>(dArray),
sizeof(dArray));
/*NB: we can also just use (char*) in place of
reinterpret_cast<char *>
*/
reinterpret_cast: To produces a value of a new type that has the same bit
pattern as its argument
Example:
double x[3];
[Link](reinterpret_cast<char*>x, sizeof(x));
/*Now you can access content read in an array x */
404
Example: - C++ Program to Write to a Binary File
#include <iostream>
#include <fstream>
using namespace std;
struct Product {
char productname[50];
int productid;
double price;
};
int main()
{
Product p1 = {“Mango”, 001, 200.30};
ofstream outputFile;
[Link](“[Link]”, ios::binary);
//Write Binary File
if(outputFile.is_open())
{
[Link](reinterpret_cast<char*>(&p1),sizeof(Product));
[Link]();
cout << “Product Written Successfully to a Binary File!!”;
}
else
{
cout << “Could not create file “;
}
return 0;
}
405
Example: - C++ Program to Read from a Binary File
#include <iostream>
#include <fstream>
using namespace std;
struct Product {
char productname[50];
int productid;
double price;
};
int main()
{
Product p2 = {};
ifstream inputFile;
[Link](“[Link]”, ios::binary);
// Read Binary File
if(inputFile.is_open())
{
[Link](reinterpret_cast<char*>(&p2),
sizeof(Product));
[Link]();
}
else
{
cout << “Could not read file “;
}
cout << [Link] << “, “ << [Link] << “, “ <<
[Link] << endl;
return 0;
}
Activity 14.4
Highlight the differences between binary and text files.
406
14.5. Random File Access
Random file access is a powerful feature in C++ that enables direct manipulation of
specific locations within a file, as opposed to sequential access from the beginning. This
capability is particularly useful when dealing with large datasets or complex file structures.
In C++, random file access is achieved through the use of the seekg() and seekp()
methods for reading and writing, respectively.
Example:
Syntax:
[Link](offset, position);
or
[Link](offset, position);
Where:
o offset: The number of bytes to move.
o position: The starting position, e.g., ios::beg for beginning,
ios::cur for current position, ios::end for end.
407
Example:
[Link](10, ios::beg);//Move to the 11th byte from the beginning
int data;
[Link](reinterpret_cast<char*>(&data), sizeof(int));
Example:
[Link](20, ios::beg); // Move to the 21st byte from the beginning
int newData = 42;
[Link](reinterpret_cast<const char*>(&newData),sizeof(int));
int main() {
fstream file("[Link]", ios::in | ios::out | ios::binary);
if (!file) {
cerr << "Unable to open file!" << endl;
return 1;
}
// Move to the 5th byte from the beginning
[Link](4, ios::beg);
// Write a new value at this position
int newValue = 100;
[Link](reinterpret_cast<const char*>(&newValue), sizeof(int));
// Move to the 10th byte from the beginning
[Link](9, ios::beg);
// Read the value at this position
int readValue;
[Link](reinterpret_cast<char*>(&readValue), sizeof(int));
cout << "Value at position 10: " << readValue << endl;
[Link]();
return 0;
}
408
14.5.5. tellp() and tellg() methods
The tellg() and tellp() methods in C++ are invaluable companions to seekg()
and seekp() when it comes to managing file positions.
streampos: is a type defined in the C++ Standard Library that represents a position
within a stream. It is used to store and manipulate file positions, specifically for file input
and output operations.
When you perform file operations like reading or writing, the tellg() and tellp()
methods return a value of type streampos, which represents the current position in the
input or output stream, respectively.
Example:
streampos currentPosition = [Link]();//Get current read position
[Link](0, ios::end); // Move to the end of the file
streampos endPosition = [Link](); // Get the end position
409
Example: A modified C++ Program using tellg() for enhanced random file access:
#include <iostream>
#include <fstream>
using namespace std;
int main() {
fstream file("[Link]", ios::in | ios::out |
ios::binary);
if (!file) {
cerr << "Unable to open file!" << endl;
return 1;
}
[Link]();
return 0;
}
410
tellg() and tellp() complement seekg() and seekp() by providing a means to
query the current file positions. This combination of methods enhances the precision
and flexibility of random file access, allowing to navigate, read, and write data at specific
locations within a file.
Activity 14.5
Discuss why error handling is crucial when using seekg() and read() for
random file access in C++
Unit summary
In this Unit, you have covered the following main points:
• The definition of a file as the container of content in a computer
• File organization refers to the logical arrangement of data in a file system, schemes
for file organization are: sequential file, direct or random-access file, indexed
sequential file and multi-indexed file.
• When files are processed in C++, the communication goes between hard disk file
and program via a stream. A file which the program is reading from is called
infile. A file which the program is writing to is called outfile.
• The data from infile goes to the program via an intermediary store called
instream. The data from the program goes to the outfile via an intermediary
store called outstream
• There are three steps to use files: opening, reading/writing and closing.
• To read a file, instream must be declared using ifstream first and attached to a
disk file before using that instream.
• To write to a file, outstream must be declared using ofstream first and attached
to a disk file before using that outstream.
• eof() function is used to check whether you have reached the end of file (EOF)
to stop reading.
411
• rdbuf() function is used to copy file contents from original file to another file,
include stdio.h header when using rdbuf() function.
• Binary files provide a powerful mechanism for efficiently storing and managing data
in its raw form.
• Random file access provides a flexible and efficient mechanism for working with
files, allowing direct manipulate specific portions of a file.
You have learned about file organization, how to write to a file, read from a file, and copy
files. The next chapter introduces program documentation, which involves writing
documentation that explains how software or applications work and how to use them.
412
UNIT
15 UNIT 15: PROGRAM DOCUMENTATION
Introduction
Documentation is an important part of software engineering. It is comprehensive
information on the capabilities, design details, features, and limitations of a systems or
application software. Software documentation is written text or illustration that
accompanies computer software or it either embedded in the source code. It either
explains how the software or application operate, or how to use it and may mean different
things to people in different roles. In this unit you will learn types of program
documentation, structure of a program documentation, documentation writing style as
well as document preparation process.
Unit outcomes
By the end of this unit, you must be able to:
• Define ‘program documentation’
• Explain types of program documentation
• Discuss components to be included in a program documentation
• Learn how to produce a good program documentation
• Explore document preparation process
Key terms
Ensure that you understand the following key terms or phrases used in this unit: program
documentation, process documentation, product documentation, system documentation,
user documentation, end-users, system administrators, document structure, document
preparation, document creation, document polishing and document production
413
15.1 Program Documentation
Program documentation is written text or illustration that either explain how the software
or application operate, or how to use it. It enlists capabilities, design details, features, and
limitations of a systems. The documents associated with a software project and the
system being developed have a number of associated requirements:
• They should act as a communication medium between members of the
development team.
• They should provide information for management to help them plan, budget and
schedule the software development process.
• They should be an information repository to be used by maintenance engineers
• Tell users how to use and administer the system.
• They may be essential evidence to be presented to a regulator for system
certification
414
Process Documentation
Process documentation is produced so that the development of the system can be
managed. Effective management requires the process being managed to be visible. It is
an essential component of plan-driven approaches. An important goal of agile
approaches is to minimize the amount of process documentation produced as this adds
overhead without contributing to the functionality of the system being developed. Process
documentation falls into a number of categories:
1. Plans, estimates and schedules: - These are documents produced by managers
which are used to predict and to control the software process.
2. Reports: - These are documents which report how resources were used during
the process of development.
3. Standards: - These are documents which set out how the process is to be
implemented. These may be developed from organizational, national or
international standards.
4. Working papers: - These are often the principal technical communication
documents in a project. They record the ideas and thoughts of the engineers
working on the project. They are interim versions of product documentation,
describe implementation strategies and set out problems which have been
identified. They often, implicitly, record the rationale for design decisions.
5. Memos and electronic mail messages: - These record the details of everyday
communications between managers and development engineers.
415
Product Documentation
Product documentation is concerned with describing the delivered software product.
Unlike most process documentation, it has a relatively long life. It must evolve in step with
the product that it describes. Product documentation includes:
1. User documentation: - which tells users how to use the software product.
2. System documentation: - which is principally intended for maintenance
engineers.
1. User Documentation
Users of a system are not all the same. The producer of documentation must structure
it to cater for different user tasks and different levels of expertise and experience. It is
particularly important to distinguish between end-users and system administrators:
i. End-users: - They use the software to assist with some task. They want to
know how the software can help them. They are not interested in computer or
administration details
ii. System administrators: - System administrators are responsible for
managing the software used by end-users. This may involve acting as an
operator
To cater for these different classes of user and different levels of user expertise, there are
at least 5 documents which should be delivered with the software system:
i. Functional description: - Outlines the system requirements and briefly describes
the services provided. Provides an overview of the system’s purpose and a
description of the most important system services. This is for Managers and
system evaluators. Users should be able to read this document with an
introductory manual and decide if the system is what they need.
416
iii. Introductory manual: - Informal introduction to the system, describing its ‘normal’
usage. It should describe how to get started and how end-users might make use
of the common system facilities. It is intended for novice users.
iv. System reference manual: - Should describe the system facilities and their
usage, should provide a complete listing of error messages and should describe
how to recover from detected errors. This document is for experienced users.
2. System Documentation
System documentation includes all of the documents describing the system itself from
the requirements specification to the final acceptance test plan. Documents describing
the design, implementation and testing of a system are essential if the program is to
be understood and maintained. Like user documentation, it is important that system
documentation is structured, with overviews leading the reader into more formal and
detailed descriptions of each aspect of the system.
For large systems that are developed to a customer’s specification, the system
documentation should include:
• The requirements document.
• A document describing the system architecture.
• For each program in the system, a description of the architecture of that
program.
• For each component in the system, a description of its functionality and
interfaces.
417
• Program source code listings: - Which should be commented where the
comments should explain complex sections of code and provide a rationale for
the coding method used.
• Validation documents describing how each program is validated and how the
validation information relates to the requirements.
• A system maintenance guide, which describes known problems with the
system, describes which parts of the system are hardware and software
dependent and which describes how evolution of the system has been taken
into account in its design.
Activity 15.1
What is the main purpose of program documentation?
ii. Documents longer than a few pages should be organized into chapters, with each
chapter further divided into sections and subsections. A contents page should be
included to list all chapters, sections, and subsections.
418
iv. If a document is intended for a wide spectrum of readers who may have differing
vocabularies, a glossary should be provided which defines the technical terms and
acronyms used in the document.
419
• Keep paragraphs short
• Don’t be verbose
• Be precise and define the terms which you use
• If a description is complex, repeat yourself
• Make use of headings and sub-headings
• Itemize facts wherever possible
• Do not refer to information by reference number alone
Activity 15.2
What are the elements of a technical document?
420
Figure 15.1: Document preparation process (Adapted from Sommerville, 2015, ch
30, p. 17)
421
The final stage of document production is a skilled task that for documents with large
print runs, should be left to professional printers.
The main advantage with on-line documentation is its accessibility. It is not necessary
for users to find manuals, there is no possibility of picking up out-of-date documentation
and search facilities can be used to locate information quickly.
Activity 15.3
What is a documentation plan?
422
Unit summary
In this Unit, you have covered the following main points:
• Program documentation is used to describe the system to its users and to software
engineers who are responsible for maintaining the system.
• Documentation produced during a software project can be divided into process
documentation and product documentation.
• Product documentation includes user documentation which tells users how to use
the software product and system documentation which is principally intended for
maintenance engineers.
• Program documents should be well-structured and written using simple and clear
language.
• Document preparation is the process of creating a document and formatting it for
publication and it has stages of document creation, document polishing and
document production.
You have learnt program documentation as text or illustrations that explains how the
program operates, or how to use it. You have also learnt types of program documentation
as well as how to write a good program documentation.
423
GLOSSARY
Acceptance Testing: Acceptance testing is the final phase of software testing where
the software is tested for its compliance with business requirements. It is usually the last
step before the software is released to the end-users.
Access specifiers: Keywords in a class that define the visibility of its members. The
common ones are public, private, and protected.
Array: An array is a finite ordered collection of homogeneous data elements that provides
direct access (or random access) to any of its elements.
Base address: Base address means the location of the first element of the array in the
memory. Base address helps in identifying the address of all the elements of the array
424
in the first half of the list, else the target will be searched in the second half of the list. The
same process is repeated for one of the halves of the list till the list reduces to the list of
size one.
Class Templates: Class templates enable the creation of generic classes that can handle
multiple data types, making it easier to create flexible data structures like stacks, queues,
and lists.
Class: A blueprint for creating objects. It defines attributes and behaviors that the objects
created from the class will have.
Comment: A comment is text that the compiler ignores but that is useful to programmers.
Compiler: compiler is a program that translates program in high level language into
machine language, the whole program is scanned and translated first before execution
Constructors: Special member functions in a class that are called when an object is
created. They initialize the object's attributes and provide a way to set up the object.
Containers: Containers are STL classes used to store collections of data, such as vector,
list, map, and stack.
Data type: A data type is a classification that specifies which type of value a variable has
and what type of mathematical, relational or logical operations can be applied to it without
causing an error.
425
Debugger: A debugger allows a programmer to more easily trace a program’s execution
in order to locate and correct errors in the program’s implementation
Dereference operator: * is the dereference operator and can be read as “value pointed
by” or “the content of”.
Derived class: A class that inherits from another class. It can have its own additional
attributes and behaviors.
Destructors: Special member functions in a class that are called when an object is
destroyed. They clean up resources and perform necessary tasks before the object goes
out of scope.
Dynamic binding: The process of linking a function call with the code to be executed at
runtime. Also known as late binding.
Encapsulation: The bundling of data and the methods that operate on that data into a
single unit (class). It hides the internal details of how an object works.
Executable: Is a file that a computer runs in order for it to solve a certain problem.
External sorting: Any sort algorithm that uses external memory during the sorting.
File: A file is a collection of records where each record consists of one or more fields
426
Friend functions: Functions that are not members of a class but have access to its
private and protected members. They are declared with the friend keyword in the class
that grants them access.
Function overloading: Defining multiple functions with the same name but different
parameter lists. The appropriate function is selected based on the arguments provided.
Function prototype: A function prototype is a declaration of the function that tells the
program about the type of the value returned by the function and the number and type
of arguments.
Function Templates: Function templates allow the creation of a single function that can
work with different data types, eliminating the need to write separate functions for each
type.
Function: A function is a piece of program code that performs a specific task when it is
called and it returns a value where it was called.
Functors: Functors, or function objects, are objects that can be used like functions; they
are created by overloading the operator() in a class and are often used in STL
algorithms for custom behavior.
Global variable: Global variable is defined outside all functions and is accessible to all
functions in its scope.
Header file: A header file is used to define all of the functions, variables and constants
contained in any function library that one wants to use.
Identifier: An identifier is a name that is assigned by the user for a program element
such as variable or function.
427
Indefinite loop: Indefinite loop is a loop which you cannot always tell how many times
the loop will occur.
infile: Typically used as an object representing an input file stream in C++. It's used to
read data from a file.
Infinite loop: Infinite loops keep repeating until the program is interrupted.
Inheritance: A mechanism in object-oriented programming where a class (called a
subclass or derived class) inherits attributes and behaviors from another class (called a
superclass or base class).
Inline function: An inline function is a function that is expanded inline when it is invoked,
thus saving time. The compiler replaces the function call with the corresponding function
code, which reduces the overhead of function calls.
Internal sorting: Any sort algorithm that uses main memory exclusively during the
sorting.
Interpreter: Interpreter is a program that translates program in high level language into
machine language, it translates and executes program line by line.
Iterators: Iterators are objects used to traverse through elements in STL containers,
similar to pointers, and come in various types (input, output, forward, bidirectional,
random-access).
Local variable: Local variable is defined inside a function and is not accessible outside
the function.
Lvalue: Lvalue is value that can be on either side of the assignment statement .
Machine code: Machine code is a set of instructions coded so that the computer can
use it directly without further translation
428
Memory leak: Memory leak occurs when programmers create a memory in heap and
forget to delete it.
Memory leak: Memory leak occurs when programmers create a memory in heap and
forget to delete it.
Methods: Functions that are part of a class and operate on the class's data.
Null pointer: The NULL pointer is a constant with a value of zero defined in several
standard libraries, including iostream. Assign the pointer NULL to a pointer variable in
case there is no exact address to be assigned.
Null-terminated strings: Null-terminated strings are stored with \0 (null character) at the
end.
Object: An instance of a class. It represents a real-world entity and has attributes and
behaviors defined by its class.
Operator overloading: The ability to define custom behaviors for operators. For
example, you can define how the + operator works for objects of a class.
Outfile: Typically used as an object representing an output file stream in C++, used for
writing data to a file.
Overloaded function: Overloaded functions describe the situation where there are two
or more functions with the same name defined in the same scope, but each function has
a unique signature.
429
Parameter: Parameter is a variable in function header that receives a value from a
function call.
Passes: During the sorting process, the data is traversed many times. Each traversal of
the data is referred to as a sort pass.
Pointer arithmetic: Pointer arithmetic involves incrementing (add a value to) and
decrementing (subtract a value from) a pointer.
Polymorphism: The ability of a type to exhibit different behaviors or have multiple forms.
In programming, it often refers to the ability of objects of different types to be treated as
objects of a common base type.
Post-condition: Post-condition has its condition after the body, the condition is tested
after executing the body.
Pre- condition: Pre-condition has its condition before the body, the condition is tested
(checked) first before executing the body.
Procedure: A procedure is a piece of program code that performs a specific task when
it is called and does not return a value where it was called.
430
Program documentation: Program documentation is written text or illustration that
either explain how the software or application operate, or how to use it.
Random access file: In direct or random-access file, records are not usually stored in
sequence but randomized to individual storage positions.
Recursive function: A recursive function is a function that calls itself during its execution.
Reference operator: & is the reference operator and can be read as “address of” or “the
address to”.
Rvalue: Rvalue is a value that should only appear on the right-hand side of the
assignment statement.
Sequential file: In sequential file, records are stored in the sequential order of their entry
Sequential search: The search begins with the first available record and proceeds to the
next available record repeatedly until it finds the target key or conclude that it is not found.
Size declarator: The number inside the brackets is the array’s size declarator. It indicates
the number of elements, or values, the array can hold.
431
Sort order: The order in which the data is organized, that is, ascending order or
descending order.
Sort stability: A sorting method is said to be stable if at the end of the method, identical
elements occur in the same order as in the original unsorted set.
Source code: Program instructions written as an ASCII text file; must be translated by a
compiler, interpreter or assembler into the object code for a particular computer before
execution.
Static binding: The process of linking a function call with the code to be executed at
compile-time. Also known as early binding.
Stream: A stream is an abstraction that represents a device on which input and output
operations are performed.
streampos: A type representing the current position in a stream (like a file or input/output
stream) in C++. It's often used to store and manipulate the position within the stream.
Structure: A structure is a programmer-defined data type that can hold many different
data values.
432
System Testing: System testing is the testing of a complete and fully integrated
software product. It aims to evaluate the system's compliance with specified
requirements and ensure that it meets its intended purpose.
Templates: Templates are a feature in C++ that allow you to write generic and reusable
code for functions or classes that can operate with any data type.
Translator: Translator is a computer program that converts given program written in one
programming language into functionally equivalent program in another language.
Union: A union is like a structure, except all the member variables occupy the same
memory area, so only one member can be used at a time.
Unit Testing: Unit testing is a level of software testing where individual units or
components of a software application are tested in isolation. The purpose is to validate
that each unit of the software performs as designed.
User documentation: Documentation which tells users how to use the software product.
Variable scope: Variable scope is the area of the program where the variable is valid.
Void pointers: A void pointer is a general-purpose pointer that can hold the address of
any data type, but it is not associated with any data type.
433
BIBLIOGRAPHY
Gaddis, T., Walters, J., & Muganda, G. (2020). Starting Out with C++: Early Objects
10th Edition. Hoboken: Pearson Education, Inc
Gregoire, M. (2018). Professional C++, Fourth Edition. Indianapolis: John Wiley & Sons,
Inc.
Halterman, R. L. (2015). Fundamentals of C++ Programming. Collegedale: Southern
Adventist University.
Haramundanis, K. (1998). The Art of Technical Documentation. Waltham: Imprint of
Butterworth-Heinemann.
Horton, I. (2014). Beginning C++. New York: Apress Media LLC.
IEEE. (2001). Draft Standard for Software User Documentation. New York: Institute of
Electrical and Electronics Engineers.
434
Kirch-Prinz, U., & Prinz, P. (2002). A Complete Guide to Programming in C++. Sudbury:
Jones and Bartlett Publishers.
Malik, D. (2010). Data Structures Using C++, Second Edition. Boston: Course
Technology, Cengage Learning.
Malik, D. (2011). C++ Programming: From Problem Analysis to Program Design, Fifth
Edition. Boston: Course Technology, Cengage Learning.
Matt, A. (2017, October 12). A Gentler Introduction to Programming. Retrieved from
freecodecamp: [Link]
programming-1f57383a1b2c/
Patil, V. H. (2012). Data Structures Using C++. New Delhi: Oxford University Press.
Pohl, I. (2002). C++ by Dissection. Boston: Addison-Wesley.
Rao, S. (2016). C++ in One Hour a Day, Sams Teach Yourself. Carmel: Sams
Publishing.
Robertson, L. A. (2007). Simple Program Design -a step by step approach (4th edition).
Sydney: Nelson Australia Pty Limited.
Silyn-Roberts, H. (2001). Writing for Science and Engineering: Papers, Presentations
and Reports. Waltham: Butterworth-Heinemann.
Sommerville, I. (2015). Software Engineering. Edinburgh: Pearson Education Limited.
Soulié, J. (2018, August 21). C++ Language Tutorial. Retrieved from cplusplus:
[Link]
Stroustrup, B. (2022). A Tour of C++. Boston: Addison-Wesley Professional.
Sun Technical Publications . (2010). Read Me First: A Style Guide for the Computer
Industry (Third Edition). New Jersey: Prentice Hall.
435