0% found this document useful (0 votes)
7 views449 pages

Lecture Notes - Programming

The document is a set of lecture notes for a Programming course within the Bachelor of Science programs at the School of Science and Technology. It covers foundational programming concepts, particularly focusing on C++ programming, including data types, control structures, functions, arrays, and object-oriented programming. The content is intended solely for academic purposes and includes a comprehensive curriculum outline with various units and topics to be covered throughout the course.

Uploaded by

dzanjalimodzih
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
7 views449 pages

Lecture Notes - Programming

The document is a set of lecture notes for a Programming course within the Bachelor of Science programs at the School of Science and Technology. It covers foundational programming concepts, particularly focusing on C++ programming, including data types, control structures, functions, arrays, and object-oriented programming. The content is intended solely for academic purposes and includes a comprehensive curriculum outline with various units and topics to be covered throughout the course.

Uploaded by

dzanjalimodzih
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

SCHOOL OF SCIENCE AND TECHNOLOGY

DEPARTMENT OF COMPUTER SCIENCE AND INFORMATION


SYSTEMS

Bachelor of Science in Management Information Systems


Bachelor of Science in Information Technology
Bachelor of Science in Software Engineering
Bachelor of Science in Cybersecurity

Year 1

PROGRAMMING

Lecture Notes

Developed by
Michael R Chinguwo

: +265 (0) 993 195 721 :mchinguwo@[Link]


DISCLAIMER
This document is intended solely for academic purposes and to support teaching and
learning. Any use for economic or commercial purposes is strictly prohibited. Users are
not permitted to distribute, share, or disseminate the content, and its use is limited to the
advancement of individual knowledge.

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

Table 1.1: Well-Known High-Level Programming Languages ......................................... 6


Table 2.1: Primitive Data Types .................................................................................... 26
Table 2.2: Type Modifiers .............................................................................................. 27
Table 2.3: Basic Fundamental Data Types in C++ ........................................................ 27
Table 2.4: C++ Reserved Words ................................................................................... 39
Table 3.1: Algebraic and C++ Multiplication Expressions.............................................. 48
Table 3.2: Algebraic and C++ Expressions ................................................................... 49
Table 3.3: Combined Assignment Operators ................................................................ 51
Table 3.4: Logical AND ................................................................................................. 53
Table 3.5: Logical OR.................................................................................................... 54
Table 3.6: Logical NOT ................................................................................................. 55
Table 4.1: Flowchart Symbols ....................................................................................... 82
Table 5.1: Where To Place a Function Definition in a Program .................................. 131
Table 8.1: Selection Sort ............................................................................................. 197
Table 8.2: Bubble Sort................................................................................................. 199
Table 8.3: Insertion Sort .............................................................................................. 202
Table 10.1: Union vs Structure .................................................................................... 240
Table 11.1: Two-Dimensional String Array .................................................................. 258
Table 12.1: Composition vs Inheritance ...................................................................... 304
Table 12.2: Key Differences: Inheritance vs Composition .......................................... 306

iii
LIST OF FIGURES

Figure 1.1: Source code to target code sequence ........................................................ 11


Figure 1.2: Process of translating a C++ source file into an executable file .................. 12
Figure 1.3: Screen from the DEV C++ IDE .................................................................... 14
Figure 3.1: Mathematical expression............................................................................. 45
Figure 3.2: Conditional operator .................................................................................... 56
Figure 3.3: Operator precedence .................................................................................. 59
Figure 4.1: Flowchart for a program that sum two given numbers ................................ 83
Figure 5.1: Sequential program control structures general flowchart ............................ 91
Figure 5.2: Simple if Statement Program Control Structures General Flowchart ....... 95
Figure 5.3: The if-else Statement Program Control Structures General Flowchart . 98
Figure 5.4: if-else if statement program control structures general flowchart .... 101
Figure 5.5: CASE statement program control structures general flowchart ................. 107
Figure 5.6: While … do Loop general flowchart ...................................................... 109
Figure 5.7: Do … while loop general flowchart........................................................ 111
Figure 5.8: Repeat … until loop general flowchart .............................................. 113
Figure 5.9: For loop general flowchart ........................................................................ 115
Figure 6.1: Value Parameters ..................................................................................... 139
Figure 6.2: Value parameters and memory location .................................................... 140
Figure 6.3: Reference Parameters .............................................................................. 140
Figure 7.1: Graphical Representation of an Array of n Numbers ................................ 170
Figure 7.2: hours array - enough memory to hold six int value ................................. 171
Figure 7.3: 2D array of 3 students with 5 grades ......................................................... 174
Figure 9.1: Reference and Dereference Operators ..................................................... 209
Figure 9.2: Pointer Operators ...................................................................................... 209
Figure 9.3: Pointer Arithmetic- integer variable ........................................................... 215
Figure 9.4: Pointer Arithmetic- double variable ........................................................... 215
Figure 9.5: Pointer of Pointer illustration ..................................................................... 216
Figure 11.1: Graphical representation of Null-terminated strings ................................ 252
Figure 14.1: File streams ............................................................................................ 394
Figure 15.1: Document preparation process .............................................................. 421

iv
TABLE OF CONTENTS

LIST OF TABLES .......................................................................................................... iii


LIST OF FIGURES......................................................................................................... iv
MODULE OVERVIEW .................................................................................................... x
UNIT 1: INTRODUCTION TO PROGRAMMING ............................................................ 1
Introduction .................................................................................................................. 1
Unit outcomes .............................................................................................................. 1
Key terms ..................................................................................................................... 1
1.1 Computer Programming ......................................................................................... 1
1.2 Programming Languages ....................................................................................... 2
1.3 Software Development Tools ................................................................................. 8
1.4 Programming Stages ........................................................................................... 14
Unit summary ............................................................................................................. 16

UNIT 2: INTRODUCTION TO C++ PROGRAMMING ................................................... 18


Introduction ................................................................................................................ 18
Unit outcomes ............................................................................................................ 18
Key terms ................................................................................................................... 18
2.1 C++ Program Structure ........................................................................................ 19
2.2 Data Types and Variables .................................................................................... 25
Unit summary ............................................................................................................. 41

UNIT 3: OPERATORS AND EXPRESSIONS ............................................................... 42


Introduction ................................................................................................................ 42
Unit outcomes ............................................................................................................ 42
Key terms ................................................................................................................... 42
3.1 Program statement .............................................................................................. 42
3.2 Expression statement........................................................................................... 45
3.3 Precedence and Associativity .............................................................................. 59
3.4 Errors and Warnings ............................................................................................ 60
3.5 Program Testing and Debugging ......................................................................... 62
Unit summary ............................................................................................................. 67

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

UNIT 5: PROGRAM CONTROL STRUCTURES .......................................................... 89


Introduction ................................................................................................................ 89
Unit outcomes ............................................................................................................ 89
Key terms ................................................................................................................... 89
5.1 Program Control Structures ................................................................................. 90
5.2 Selection Program Control Structures .................................................................. 92
5.3 Loop/Iteration program control structures .......................................................... 107
Unit summary ........................................................................................................... 119

UNIT 6: FUNCTIONS .................................................................................................. 120


Introduction .............................................................................................................. 120
Unit outcomes .......................................................................................................... 120
Key terms ................................................................................................................. 120
6.1 Modular Programming........................................................................................ 121
6.2 User-defined functions ....................................................................................... 129
6.3 Variable Scope ................................................................................................... 151
6.4 Memory Management ........................................................................................ 157
Unit summary ........................................................................................................... 160

UNIT 7: ARRAYS........................................................................................................ 161


Introduction .............................................................................................................. 161
Unit outcomes .......................................................................................................... 161
Key terms ................................................................................................................. 162
7.1. Introduction to Data Structures ......................................................................... 162

vi
7.2. Array ................................................................................................................. 169
7.3. Two-Dimensional Arrays ................................................................................... 174
7.4. Manipulating Array Contents ............................................................................. 177
Unit summary ........................................................................................................... 183

UNIT 8: SEARCHING AND SORTING ARRAY ELEMENTS ..................................... 184


Introduction .............................................................................................................. 184
Unit outcomes .......................................................................................................... 184
Key terms ................................................................................................................. 184
8.1. Searching and Sorting....................................................................................... 185
8.2. Searching Algorithms ........................................................................................ 188
8.3. Sorting Algorithms ............................................................................................. 196
Unit summary ........................................................................................................... 204

UNIT 9: POINTERS .................................................................................................... 206


Introduction .............................................................................................................. 206
Unit outcomes .......................................................................................................... 206
Key terms ................................................................................................................. 207
9.1. Pointer............................................................................................................... 207
9.2. Arrays and Pointers .......................................................................................... 212
9.3. Functions and Pointers ..................................................................................... 217
9.4. Dynamic Memory .............................................................................................. 220
Unit summary ........................................................................................................... 226

UNIT 10: STRUCTURES ............................................................................................ 227


Introduction .............................................................................................................. 227
Unit outcomes .......................................................................................................... 227
Key terms ................................................................................................................. 227
10.1. Structure ......................................................................................................... 228
10.2. Nested Structures ........................................................................................... 233
10.3. Arrays and Structures ..................................................................................... 235
10.4. Functions and Structures ................................................................................ 236
10.5. Unions ............................................................................................................. 239
10.6 Enumerations (Enums) .................................................................................... 243

vii
Unit summary ........................................................................................................... 248

UNIT 11: STRINGS MANIPULATION ........................................................................ 249


Introduction .............................................................................................................. 249
Unit outcomes .......................................................................................................... 249
Key terms ................................................................................................................. 249
11.1. Data Type Char ............................................................................................... 250
11.2. Working with Strings ....................................................................................... 252
11.3. Array of Strings ............................................................................................... 258
Unit summary ........................................................................................................... 263

UNIT 12: OBJECT-ORIENTED PROGRAMMING CONCEPTS ................................. 264


Introduction .............................................................................................................. 264
Unit outcomes .......................................................................................................... 264
Key terms ................................................................................................................. 265
12.1. Programming Paradigms ................................................................................ 265
12.2. Classes and Objects ....................................................................................... 275
12.3. Inheritance ...................................................................................................... 298
12.4. Polymorphism ................................................................................................. 318
12.5. Encapsulation ................................................................................................. 332
12.6. Abstraction ...................................................................................................... 337
12.7. Message Passing ............................................................................................ 344
12.8 Interfaces ......................................................................................................... 348
12.9. Modeling Real-World Systems with OOP........................................................ 352
Unit summary ........................................................................................................... 356

UNIT 13: TEMPLATES ............................................................................................... 358


Introduction .............................................................................................................. 358
Unit outcomes .......................................................................................................... 358
Key terms ................................................................................................................. 359
13.1. Understanding Templates ............................................................................... 359
13.2. Standard Template Library (STL) .................................................................... 377
13.3. Trending and Emerging Technologies in C++ ................................................. 384
Unit summary ........................................................................................................... 388

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

UNIT 15: PROGRAM DOCUMENTATION ................................................................. 413


Introduction .............................................................................................................. 413
Unit outcomes .......................................................................................................... 413
Key terms ................................................................................................................. 413
15.1 Program Documentation .................................................................................. 414
15.2 Document Structure ......................................................................................... 418
15.3 Document Preparation ..................................................................................... 420
Unit summary ........................................................................................................... 423
GLOSSARY ................................................................................................................ 424
BIBLIOGRAPHY ......................................................................................................... 434

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.

The Programming subject focuses on introducing foundational principles of computer


program development using a systematic problem-solving approach. Students learn to
analyze both functional and non-functional requirements, design algorithms using
flowcharts, natural language, and pseudocode, and gain hands-on experience in coding
and testing programs using Integrated Development Environments (IDEs).

Throughout the course, students are introduced to fundamental programming concepts


and progressively advance to more complex topics, including data management, data
analysis, and object-oriented programming. They also acquire essential skills in
implementing basic data structures, understanding object-oriented programming
principles, developing applications, and processing files within programs.

In Programming, you will cover the following units:

Unit 1: Introduction to Programming


This unit introduces programming fundamentals, computer program, computer
programming, program execution, programming languages, program development tools,
programming language generations and programming stages.

Unit 2: Introduction to C++ Programming


This unit gets you started in C++ by introducing the basic parts of a C++ program such
as key words and punctuation. This unit also introduces data types, variable definitions,
assignment statements, constants, comments, program output, and simple arithmetic
operations. It also introduces rules for naming variables and constants in C++.

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 4: Program Design


In this unit, you'll acquire knowledge on algorithms and various algorithm notations,
including natural language, pseudo code, and flowcharts. The focus of this unit is on
program design, where you'll engage in the problem-solving phase to gather program
requirements. Subsequently, you'll transition to the implementation phase, converting the
formulated algorithm into a programming language.

Unit 5: Program Control Structures


This unit introduces three program control structures: Sequential, Selection and Iteration.
You will learn how to control the flow of a program with the if, if/else, and if/else
if statements. The switch statement is also covered in this unit and applications of
these constructs, such as menu-driven programs, are also illustrated. This unit also
covers C++’s repetitive control mechanisms. The while loop, do-while loop, and for
loop are taught, along with a variety of methods to control them.

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 8: Searching and Sorting Array Elements


This unit explains the basic search and sort techniques that help make the search process
more efficient. In this unit students will acquire a foundational understanding of searching
for information in arrays and arranging array elements. The unit covers the Linear Search,
Binary Search, Bubble Sort, Insertion Sort and Selection Sort algorithms.

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.

Unit 10: Structures


This unit introduces how to define a structure in a program with struct keyword,
declaring and initiating structure variables, assigning values to structure members. This
unit also covers nested structures, arrays and structures and functions and structures.

Unit 11: Strings Manipulation


This unit defines a string and ways of handling strings which includes using null-
terminated strings – C-type strings and using string class. The unit also explains C- type
strings functions such as functions for determining the length of a string, for concatenating
two strings, for copying strings, for comparing two strings, and for searching for the
occurrence of one string within another. Array of strings are also covered in this unit.

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.

Unit 13: Templates


In this unit, we’ll dive into the power of C++ templates. Templates let you write flexible
and reusable code without repeating yourself. You’ll learn how to create functions and
classes that work with different data types using just one definition. Discover the
difference between function templates and class templates, and see how they help when
working with arrays, numbers, or even custom objects. By the end, you’ll know how
templates can make your code shorter, smarter, and easier to maintain—perfect for
solving the same problem across different types.

Unit 14: File Handling


This unit explores file organization schemes, including sequential and random access. It
delves into different file opening modes and explores various techniques for reading and
writing both text and binary file contents. Students will gain familiarity with file I/O classes
like ifstream, ofstream, and fstream. Additionally, the unit covers the process of
copying a file using the rdbuf() function.

Unit 15: Program documentation


In this unit, we'll explore various forms of documentation, including process
documentation and product documentation. The module delves into the different
categories of product documentation and covers the key features of process
documentation. You'll gain insights into structuring program documents, organizing them
into chapters, sections, and subsections. Additionally, the unit will touch upon document
writing style and document preparation.

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.1 Computer Programming


1.1.1 Computer program
Computer program is a set of instructions that tells a computer(hardware) to do a
particular task. It can also be defined as a collection of instructions, performing a specific
task or solve a problem when executed by a computer. A program is also called software.

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.

1.1.2 Computer programming


Computer programming is a process of writing set of instructions that tells a computer
(hardware) to do a particular task. It is considered to be a process of writing a computer
program. Is the act of writing instructions in a way that allows a computer to understand
and execute those instructions. The instructions themselves are called source code. A
person who writes (develops) a computer program is called programmer.

Running of a program in a computer is called execution. When your program is being


executed, it means lines of instructions which make up that program are being fetched
and processed by the Central Processing Unit (CPU). The end result of programming is
that you have an executable file. An executable is a file that your computer can run in
order for it to solve a certain problem.

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?

1.2 Programming Languages


1.2.1 Programming language
Communication with a computer is done by using programming language.
Programmers write instructions in various programming languages, some directly
understandable by computers and others requiring intermediate translation steps.
Computer’s language is machine language, language which computer does not require
any translation. Machine language is binary which is in 0s and 1s. But it’s hard to

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?

1.2.2 Language Elements


There are certain elements that are common to all programming languages. All
programming languages have the following things in common:
i. Key words
Words that have a special meaning. Key words may only be used for their intended
purpose. Key words are also known as reserved words.

ii. Programmer-defined identifiers


Words or names defined by the programmer. They are symbolic names that refer
to variables or programming routines.

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.

1.2.3 Language Syntax and Semantics


Each computer language just like any other language has got its own grammar and
vocabulary. A sentence of programming language is called a program statement.

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.

To illustrate, the sentence:


The tall boy runs quickly to the door.
uses proper English syntax. By comparison, the sentence
Boy the tall runs door to quickly the.
is not correct syntactically. It uses the same words as the original sentence, but their
arrangement does not follow the rules of English.
Similarly, programmers must follow strict syntax rules to create well-formed computer
programs. Only well-formed programs are acceptable and can be compiled and executed.

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:

Table 1.1: Well-Known High-Level Programming Languages


Language Description
C A structured, general-purpose language which offers
both high-level and low-level features
C++ Based on the C language, C++ offers object-oriented features not
found in C
C# A language invented by Microsoft for developing applications based
on the Microsoft .NET platform.
Java An object-oriented language invented. May be used to develop
programs that run over the Internet in a Web browser
JavaScript A language used to write small programs that run in Web pages, not
related to Java
Python A general-purpose language. It has become popular for both
business and academic applications.
Ruby A general-purpose language, for programs that run on Web servers.
Visual Basic A Microsoft programming language and software development
environment that allows programmers to quickly create Windows-
based applications.
PHP Is an object-oriented, used by numerous websites, supports many
databases
Perl Object-oriented scripting languages for web programming.
Ada Supports object-oriented programming
COBOL Common Business-Oriented Language. A language designed for
business applications.
Basic A general programming language originally designed to be simple
enough for beginners to learn.
Pascal It was designed for teaching structured programming
FORTRAN Formula Translator. A language designed for programming complex
mathematical algorithms.

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

ii. Second Generation Programming Language (2GL)


• Assembly language - the human-readable notation for the machine
language used to control specific computer operations
• Assembler is a program that translates assembly language into machine
language
• Assembly language has one-to-one correspondence between machine
instructions and assembly instructions
• Programmer thinks like a machine.
• Machine-dependent

iii. Third Generation Programming Language (3GL)


• Uses high-level primitives
• Each primitive corresponds to a sequence of machine language instructions
• Translator that translates 3GL languages into machine code is Compiler or
Interpreter
• Machine independent (mostly)

iv. Fourth Generation Programming Language (4GL)


• A very high-level programming language
• Goal-oriented programming language
• Might use syntax that is never used in other programming languages

7
• Often used to access data in a database
• Example is SQL (Structured Query Language)

v. Fifth Generation Programming Language (5GL


• Visual Programming languages
• Constraint-based and logic programming languages
• Contain visual tools to help develop a program
• Designed to make the computer solve a given problem without the
programmer
• Examples are Visual Basic, Prolog, Mercury.

Activity 1.2b
Discuss the differences between a high-level language and a low-level
language?

1.3 Software Development Tools


Software development tools refer to a set of programs, applications, or platforms
designed to aid and streamline the process of creating, testing, and deploying software.
These tools encompass a wide range of functionalities, including code editing, version
control, collaboration, project management, testing, and automation. Their purpose is to
enhance the efficiency, quality, and collaboration within the software development
lifecycle.

1.3.1 Development Tools


Software can be represented by printed words and symbols that are easier for humans
to manage than binary sequences. Tools exist that automatically convert a higher-level
description of what is to be done into the required lower-level code. Programmers have a
variety of tools available to enhance the software development process. Some common
tools include:

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)

Compilation Process Explanation


An editor is used to type and save the source code, the file they are saved in is called the
source file. After the source code is saved to a file, the process of translating it to machine
language can begin. A source file is sent to a compiler. Your source is enhanced with
libraries source code (These libraries are included in a source file by #include e.g
iostream.h). Enhanced source code is produced. Compiler translates the whole source
code into object code (machine code). Object code is combined with other libraries using

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.

1.3.3 Integrated Development Environments (IDEs)


Many developers use integrated development environments (IDEs). An IDE includes
editors, debuggers, and other programming aids in one comprehensive program. These
environments consist of a text editor, compiler, debugger, and other utilities integrated
into a package with a single set of menus. Preprocessing, compiling, linking, and even
executing a program is done with a single click of a button, or by selecting a single item
from a menu.

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?

1.4 Programming Stages


Programming is complicated process; different programs are written with different
languages; the following are stages of programming:
i. Specification
ii. Design
iii. Coding
iv. Testing
v. Documentation

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.

2.1.1 The Parts of a C++ Program


C++ programs have parts and components that serve specific purposes. Every C++
program has an anatomy. Unlike human anatomy, the parts of C++ programs are not
always in the same place. Properly written C++ programs have a particular structure. The
syntax must be correct, or the compiler will generate error messages and not produce
executable machine language.

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.

General syntax is:


cout<< “message here”;
Where:
• << is called output redirection symbol
• message here is where you have to type what to be displayed on the monitor
Example
#include<iostream>
using namespace std;
int main()
{
cout<< “Welcome to C++ programming”;
return 0;
}

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.

With using namespace std; use short name (cout)


#include<iostream>
using namespace std;
int main()
{
cout<< “Welcome to C++ programming”;
return 0;
}

Without using namespace std; use long name (std::cout)


#include<iostream>
int main()
{
std::cout<< “Welcome to C++ programming”;
return 0;
}

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

Single-line or line comment


• Comments just a line or portion of it.
• Starts with double slashes (//). The compiler ignores everything from that point to
the end of the line.
• Example: // this is a line comment.

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.

2.2 Data Types and Variables


In programming language, you need to use various variables to store various information.
Variables are nothing but reserved memory locations to store values. This means that
when you create a variable you reserve some space in memory. Based on the data type
of a variable, the operating system allocates memory and decides what can be stored in
the reserved memory. C++ offer the programmer a rich assortment of built-in as well as
user defined data types.

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.

2.2.1 Data Types


There are many different types of data. Variables are classified according to their data
type, which determines the kind of information that may be stored in them. Integer
variables can only hold whole numbers. Computer programs collect pieces of data from
the real world and manipulate them in various ways. There are many different types of
data.

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

[Link] Primitive Data Types


These are the fundamental data types available in C++.

Table 2.1: Primitive Data Types


Data Type Description Example

int Stores integers int num = 10;

float Stores floating-point numbers float pi = 3.14;

double Stores double-precision floating-point double pi = 3.14159;


numbers
char Stores a single character char letter = 'A';

bool Stores Boolean values (true or false) bool isPassed = true;

void Represents absence of type (used for void display();


functions)

Type Modifiers
Several of the basic types can be modified using one or more of these type modifiers:
• signed
• unsigned
• short
• long

C++ provides type modifiers to change the properties of data types.

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;

short Uses less memory than int short int num;

long Uses more memory than int long int num;

Table 2.3: Basic Fundamental Data Types in C++


Data Type Description Size Range
char Character or small 1 byte Signed: -128 to +127
integer Unsigned: 0 to 255
short int Short Integer 2 bytes Signed: -32768 to +32767
(short) Unsigned:0 to 65535
int Integer 4 bytes Signed: -2147483648 to
+2147483647
Unsigned: 0 to 4294967295
bool It takes one of the two 1 byte True or False
values: true or false
float Floating point number 4 bytes 1.17549 x 10-38 to 3.40282 x 10+38
(~7 digits)
double Double precision 8 bytes 2.22507 x 10-308 to 1.79769 x 10+308
floating point number (~15 digits)
long Long double precision 8 bytes 2.22507 x 10-308 to 1.79769 x 10+308
double floating point number (~15 digits)
wchar_t Wide character 2 or 4 1 wide character
bytes

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.

Why Type Casting is Important


• To avoid data type mismatch errors
• To perform calculations involving different data types

28
• To control memory usage and precision
• To convert user input into required data types

Types of Type Casting in C++


C++ supports two main types of type casting:
1. Implicit Type Casting (Automatic Type Conversion)
2. Explicit Type Casting (Manual Type Conversion)

1. Implicit Type Casting (Automatic Type Conversion)


Implicit type casting is performed automatically by the compiler without the programmer’s
intervention. It usually occurs when a smaller data type is converted to a larger data type.
This is also called Type Promotion.

Example:
#include <iostream>
using namespace std;

int main() {
int num = 10;
double result = num; // Implicit conversion from int to
double

cout << "Integer value: " << num << endl;


cout << "Double value: " << result << endl;

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

[Link] Derived Data Types


Derived data types are data types that are created (derived) from primitive or basic data
types such as int, float, char, and double. They allow programmers to store and
manipulate data in more flexible and powerful ways.

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 = &num; // 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.

In C++, common user-defined data types include structures, classes, and


enumerations.

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:

enum Color { RED, GREEN, BLUE };

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.

A variable is declared as follows:


data_type variable_name;

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.

cin and variables


Mostly data assigned to variables is entered by users of the program (at a time program
is running and not during coding). cin reads a value from the keyboard. The >> symbol
is the stream extraction operator. It gets characters from the stream object on its left
and stores them in the variable whose name appears on its right.

Gathering input from the user is normally a two-step process:


i. Use cout to display a prompt on the screen.
ii. Use cin to read a value from the keyboard.
Syntax for using cin is:
cin>>variable_name;
For example:
cin>>age;
This statement will return a cursor for a user to enter a value. When the user types the
value and presses ENTER, the value entered is stored in variable called age.
Example:
#include<iostream>
using namespace std;
int main()
{
int age;
cout<<“enter your age: ”;
cin>>age; // this line is getting age from a user
cout<<“Your age is:”<<age; //this line displays age entered
return 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

ii. Using keyword const


• Placed at same location as variables i.e. after int main() {
• Declaration is similar to that of variables. But begins with const keyword
• Syntax:
const data_type constant_name = value;
• Example
const float 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;
}

Note that you cannot assign a value to a constant after declaration.

Rules for Naming Variables and Constants


Names of variables or constants should follow the rules below:
i. Name does not contain a space
• For example; int my age; my age is invalid identifier.
• Use underscore instead e.g. int my_age;

ii. Name does not start with a number.


• For example; int 1st_number; 1st_number is invalid identifier.
• Instead say int first_number; or int number1;
• It must start with a letter or an underscore ( _ )

iii. Names are case sensitive.


• For example; my_age and My_Age are different variable names due to
difference in their cases (first one is in lowercase, the second one,
some are uppercases).

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

v. Name must not be C++ keyword.


• C++ reserves these words for specific purposes in program
construction. You should not use any of these words to name a
variable.

Table 2.4: C++ Reserved Words.


alignas decltype namespace struct signed
alignof default new switch static_cast
and delete noexcept template xor_eq
and_eq double not this continue
asm not_eq do thread_local mutable
auto dynamic_cast nullptr throw inline
bitand else operator true const_cast
bitor enum or try long
bool explicit or_eq typedef const
break export private typeid xor
protected case extern for static_assert
catch false public typename wchar_t
char float register union int
using reinterpret_cast char16_t unsigned while
return virtual char32_t friend constexpr
void class goto short static
volatile if compl sizeof

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.

Example: A program that add two numbers entered by the user:


#include<iostream>
using namespace std;
int main()
{
int first, second, sum;
cout<<“enter two integers to add\n”;
cin>>first>>second;
sum = first + second;
/* Adding contents of first and second and
storing in sum */
cout<< “Sum of entered numbers = ”<<sum<<“\n”;
return 0;
}

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.

3.1 Program statement


Program statement are instructions. In C++, any expression followed by a semicolon is a
statement. These are elements in a program which ended up with a semi-colon (;). For
example, variables declaration statement; int a, b, c; Preprocessor directives (i.e.
#include and #define) are not statement, they don’t use semi-colon. Any

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.

3.1.1 Types of Statements in C++


Statements are fragments of the C++ program that are executed in sequence. The body
of any function is a sequence of statements. For example:

int main()
{
int n = 1; // declaration statement
n = n + 1; // expression statement
cout << "n = " << n << “\n”; // expression statement
return 0; // return statement
}

C++ includes the following types of statements:

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.

ii. Compound statements


Compound statements or blocks are brace-enclosed sequences of statements. When
one statement is expected, but multiple statements need to be executed in sequence
(for example, in an if statement or a loop), a compound statement may be used. Each
compound statement introduces its own block scope; variables declared inside a block
are destroyed at the closing brace in reverse order:

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

iii. Labeled Statement


Any statement can be labeled, by providing a label followed by a colon before the
statement itself.

iv. Selection statements


Selection statements choose between one of several flows of control:
• if statement;
• if statement with an else clause;
• switch statement

v. Iteration statements
Iteration statements repeatedly execute some code.
• while loop;
• do-while loop;
• for loop;

vi. Jump statements


Jump statements unconditionally transfer flow control:
• break statement;
• continue statement;
• return statement with an optional expression;
• return statement using list initialization;
• goto statement

44
vii. Declaration statements
Declaration statements introduce one or more identifiers into a block:
int num1, num2;
int num = 1;

viii. Try blocks


Try blocks provide the ability to catch exceptions thrown when executing other
statements.

Activity 3.1
Is the variable x a valid C++ expression?

3.2 Expression statement


An expression statement is a statement that result a value. A sequence of operators and
their operands, that specifies a computation. For example:

In math, an expression can be 2x – 3


Terms

2x – 3 = 1

Expression
Figure 3.1: Mathematical expression

• A minus symbol (-), in expression 2x – 3, is called an operator.


• The terms such as 2x and 3 are called operands.

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

ii. Variable expression


• Example: variable1
• Value: The content of the variable

iii. Arithmetic expression


• Example: 2+3-1
• Value: The results of the operation

Operators can be classified according to:


i. The type of their operands and of their output
• Arithmetic Operators
• Relational or comparison Operators
• Logical Operators
• Conditional Operators
• Bitwise Operators

ii. The number of their operands


• Unary Operators (one operand)
• Binary Operators (two operands
• Ternary Operators (three operands)

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.

3.2.2 Types of Expressions


The following are types of expressions:
i. Arithmetic expressions
Used to do addition, subtraction, multiplication, division and find modulus
(remainder) of numbers or variables. Operators for arithmetic expressions are
called arithmetic operators.

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.

Arithmetic expressions can be used in assignment statement


sum = num1 + num2;
or
x = 6 * 7;

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

Grouping with Parentheses


Parts of a mathematical expression may be grouped with parentheses to force some
operations to be performed before others. In the following statement, the sum of a plus b
is divided by 4.
average = (a + b) / 4;
Without the parentheses b would be divided by 4 before adding a to the result.

Converting Algebraic Expressions to Programming Statements


In algebra it is not always necessary to use an operator for multiplication. C++, however,
requires an operator for any mathematical operation. Table 3.1 shows some algebraic
expressions that perform multiplication and the equivalent C++ expressions.

Table 3.1: Algebraic and C++ Multiplication Expressions


Algebraic Expression Operation C++ Equivalent
6B 6 times B 6*B
(3)(12) 3 times 12 3 * 12
4xy 4 times x times y 4*x*y

When converting some algebraic expressions to C++, you may have to insert
parentheses that do not appear in the algebraic expression.

For example, look at the following expression:


𝒂+𝒃
X =
𝒄
To convert this to a C++ statement, a + b will have to be enclosed in parentheses:
x = (a + b) / c;

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 =
𝟓𝒂−𝟏

Arithmetic Expressions and Data Types


a. Division of integers evaluates to an integer.
integer/integer = integer
Example:
cout<<(22/7); //displays 3 and not 3.1415…
cout<<(1/2); //displays 0 and not 0.5

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;

What are the values of the following expressions?


a. b / a
b. x * a

Multiple and Combined Assignment


Multiple assignment means to assign the same value to several variables with one
statement. C++ allows you to assign a value to multiple variables at once. If a program
has several variables, such as a, b, c, and d, and each variable needs to be assigned a
value, such as 12, the following statement may be constructed:

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.

Combined Assignment Operators


Quite often programs have assignment statements of the following form:
number = number + 1;

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.

Table 3.3: Combined Assignment Operators


Operator Example Usage Equivalent To
+= x += 5; x = x + 5;
-= y -= 2; y = y - 2;
*= z *= 10; z = z * 10;
/= a /= b; a = a / b;
%= c %= 3; c = c % 3;

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

ii. Relational Expressions


These are comparison expressions. Result of relational expression is a Boolean
either True or False. They use operators such as equal to, greater than, less than,
equal to, etc. Relational operators in C ++ are:
• == (equal to operator: e.g. x==2)
• ! = (not equal to operator: e.g. x! =2)
• > (greater than operator: e.g. x>2)
• < (less than operator: e.g. x<2)
• >= (greater than or equal to: e.g. x>=2)
• <= (less than or equal to: e.g. x<=2)

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)

Logical Expressions – AND Operator


• AND (&&) evaluates to true if both operands are true otherwise false
• In other words, it evaluates to true if both relational expressions evaluate to true.
• It evaluates to true if both conditions are true.

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

Table 3.4: Logical AND


Expression Value of the Expression
false && false false (0)
false && true false (0)
true && false false (0)
true && true true (1)

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:

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 false */

Logical Expressions – OR Operator


• OR (||) evaluates to true if both or one of the operands are true otherwise false
• In other words, it evaluates to false if both conditions are false.
• All it takes for an OR expression to be true is for one of the sub-expressions to be
true. It doesn’t matter if the other sub-expression is false or true.
Table 3.5 shows a truth table for the || operator.

Table 3.5: Logical OR


Expression Value of the Expression
false || false false (0)
false || true true (1)
true || false true (1)
true || true true (1)

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.

Table 3.6: Logical NOT


Expression Value of the Expression
!false true (1)
!true false (0)

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

First expression: 3rd expression:


condition to be executes if the
tested condition is false

x < 0 ? y = 10 : z = 20;

2nd expression:
executes if the
condition is true

Figure 3.2: Conditional operator

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;

is equivalent to if/else statements below:

if(a==3)
{
x=1;
}
else
{
x=0;
}

For the statement below:

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 (? :)

3.3 Precedence and Associativity


Another problem associated with evaluating expressions is that of order of
evaluation. Should
a + b * c
be evaluated by performing the multiplication first, or by performing the addition first? i.e.
as (a + b) * c or as a + (b * c)?

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

Figure 3.3: Operator 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)

3.4 Errors and Warnings


Beginning programmers make mistakes writing programs because of inexperience in
programming in general or because of unfamiliarity with a programming language.
Seasoned programmers make mistakes due to carelessness or because the proposed
solution to a problem is faulty and the correct implementation of an incorrect solution will
not produce a correct program. Regardless of the reason, a programming error falls
under one of three categories:
i. Syntax Errors
ii. Run-time errors
iii. Logic Errors (Warning)

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”.

iii. Logic Errors


Errors in the program’s algorithm. Most difficult to diagnose. Compiler does not
recognize logical errors. Logical errors are errors that are caused by errors in the
method of solution (algorithm), thus while the incorrect statement is syntactically
correct it is asking the computer to do something which is incorrect in the context
of the application. It may be something as simple as subtracting two numbers
instead of adding them.

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?

3.5 Program Testing and Debugging


Testing is like playing detective with your code. It involves creating specific scenarios to
make sure your code does what it's supposed to do. There are different types of testing,
like unit testing (testing individual parts of your code), integration testing (testing how
different parts work together), and end-to-end testing (checking the whole system). Each
has its own merits.

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.

Program testing is a critical aspect of the software development lifecycle, offering


numerous benefits that contribute to the creation of high-quality, reliable, and user-friendly
software.

[Link] Types of Testing


There are numerous types of software testing techniques that you can use to ensure
changes to your code work as expected:
i. Unit Testing
- Testing individual components or functions in isolation.
- Verify that each unit of the program works as expected.

63
- Helps catch errors early in the development process.
- Example:
✓ Testing a specific function that performs a mathematical
operation.

ii. Integration Testing


- Testing the combination of units to ensure they work together correctly.
- Identify and fix issues related to the interaction between different
components.
- Ensures seamless integration of different parts of the program.
- Example:
✓ Verifying that the data input from one module is correctly
processed by another module.

iii. System Testing


- Testing the entire system as a whole.
- Confirm that the complete software system meets specified requirements.
- Ensures the software functions as intended in its entirety.
- Example:
✓ Testing the complete software application with all its modules
and components.

iv. Acceptance Testing


- Testing conducted to determine if the software satisfies the user's
requirements.
- Ensure the software is ready for deployment and use.
- Validates that the software meets user needs and expectations.
- Example:
✓ Testing the software with real users to ensure it meets their
expectations.

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:

➢ Error Identification: Debugging helps identify errors or defects in the code.


Allows programmers to locate and understand the root cause of unexpected
behavior or issues in the software.
➢ Improved Code Quality: Debugging contributes to the improvement of code
quality. Developers can enhance the efficiency, readability, and maintainability of
the code while addressing and fixing bugs.
➢ Optimized Performance: Debugging aids in identifying performance bottlenecks
and inefficiencies in the code. By optimizing code during the debugging process,
developers can improve the overall performance of the software.
➢ Enhanced Software Reliability: Debugging helps eliminate defects that may lead
to system failures or crashes. Results in a more reliable and stable software
application, reducing the likelihood of disruptions for end-users.
➢ Better Understanding of Code Execution: Debugging tools provide insights into
the execution flow of the code. Helps developers understand how different parts
of the program interact, aiding in the identification of logical errors.

Debugging is a fundamental aspect of the software development process that offers


numerous advantages, including error identification, code quality improvement, enhanced
software reliability, time and cost savings, and increased developer productivity.

[Link] Debugging Techniques


Debugging is a critical skill in software development, and various techniques can help
developers identify and fix issues in their code. The following are some commonly used
debugging techniques:

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.

3. Rubber Duck Debugging


- Explaining the code or problem to an inanimate object (like a rubber duck) to gain
insights.
- Encourages a detailed analysis of the code.
- Relies on the programmer's ability to articulate the problem.
- Example: Verbally describing the code and its logic to a rubber duck.

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.

A well-designed program is easy to understand, easy to maintain, and easy to modify


when requirements change.

Importance of Program Design


Program design is important for the following reasons:
i. Reduces errors and improves efficiency:
o Proper planning minimizes logical mistakes and unnecessary
computations.
ii. Enhances code readability and maintainability:
o Well-structured programs are easier for programmers to read, understand,
and modify.
iii. Makes debugging and testing easier:
o A clear design helps in identifying and fixing errors quickly.
iv. Ensures reusability of code:
o Well-designed modules and functions can be reused in other programs.

Program Development Life Cycle (PDLC)


The Program Development Life Cycle (PDLC) is a systematic process used to develop
computer programs. It consists of several phases:

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

2. Planning the Solution


In this phase, the programmer designs how the problem will be solved.

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

4. Compilation and Execution


• Compilation: The source code is translated into machine language by a
compiler.
• Execution: The compiled program is run to produce results.

5. Testing and Debugging


• Testing: Running the program with different inputs to check correctness.
• Debugging: Finding and fixing errors (bugs) in the program.

70
Types of Errors:
• Syntax errors
• Logical errors
• Runtime errors

6. Documentation and Maintenance


• Documentation: Writing explanations, comments, and user manuals for the
program.
• Maintenance: Updating and improving the program after deployment.

Understanding the Problem (IPO Model)


Before writing any program, the programmer must clearly understand the problem using
the IPO (Input–Process–Output) model.

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.

4.1.1 Types of statements


In C++ there are three basic types of statements:
• Declaration Statements
• Input / Output Statements
• Assignments Statements

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)

ii. Input / Output Statements


a. Input statements
• Input statements gets data from input device or file
• In C++, cin>> is used to get data from standard input device such as a
keyboard and put it into a variable;
• Example: cin>>age; /* This gets data from keyboard (user) and puts it
in a variable called age */

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;

4.2 Algorithm Design


4.2.1 Algorithm
Algorithm is a step-by-step problem-solving process in which a solution is arrived at in a
finite amount of time. It is a step-by-step procedure to find a solution to a problem, a
sequence of steps that should be followed to solve a problem (sequence of precise
instructions which leads to a solution). An algorithm expressed in a language that a
computer can understand is called a program.

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.

Characteristics of a Good Algorithm


An algorithm is a step-by-step procedure used to solve a problem. A well-designed
algorithm must have the following characteristics:

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:

Step 1: Understanding the Problem


• Before writing an algorithm, the problem must be clearly understood.

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

Step 2: Define the Algorithm


• After analyzing the problem, write a step-by-step solution in plain language.

Example Steps:
1. Read marks
2. Calculate total
3. Compute average
4. Display results

Step 3: Convert Algorithm into Pseudocode


• Pseudocode is a language-independent way of writing algorithms using simple
English-like statements.

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.

Step 5: Implement the Algorithm in C++


• Finally, the algorithm is translated into C++ source code.

Example:
cout << "Enter marks: ";
cin >> marks;
average = marks / 2;
cout << average;

Types of Algorithm Design Techniques


Different techniques are used to solve problems efficiently:

1. Brute Force Approach


• Tries all possible solutions until the correct one is found.

Characteristics:
o Very simple to understand
o Inefficient for large problems
Examples:
o Linear Search
o Bubble Sort

2. Divide and Conquer


• Divides a big problem into smaller subproblems, solves them recursively,
and combines the results.

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

4.2.2 Program Design


• Programming is a creative process, no complete set of rules for creating a
program.
• Program design process has following phases:

78
i. Problem solving phase
• Result is an algorithm that solves the problem

ii. Implementation Phase


• Result is the algorithm translated into a programming language

i. Problem Solving Phase


• Be certain the task is completely specified
o What is the input?
o What information is the output?
o How is the output organized?
• Develop the algorithm before implementation
o Experience shows this saves time in getting your program to run
o Test the algorithm for correctness

ii. Implementation Phase


• Translate the algorithm into a programming language, it is easier as you gain
experience with the language
• Compile the source code, this locates errors in using the programming
language
• Run the program on sample data to verify correctness of results
• Results may require modification of the algorithm and program.

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?

4.3 Algorithm notations


An algorithm can be expressed in different notations:
• Natural language
• Pseudo code and flowcharts – Design phase
• Programming language – Coding phase.

4.3.1 Algorithm by natural language


Steps to solve the problems are written using a natural language such as English. Natural
language tends to be ambiguous. Same statement can have multiple meaning hence
implemented different by different programmers. Algorithms for complex problems should
not be expressed using natural language.

Example: Write an algorithm for a program that accepts two numbers and displays their
sum.
Solution:

1. Enter/accept first number from a user


2. Enter/accept second number from the user
3. Add two numbers together
4. Display a result in (3)

4.3.2 Algorithm by Pseudocode


A pseudocode is an algorithm written in something similar to programming language but
in a more understandable format. It resembles a programming [Link] is a mixture of
C++ and ordinary English. It cannot be executed by a computer. There is no universal
standard on how pseudocodes should be written. Different programmer presents them
differently. It allows making algorithm precise without worrying about the details of C++
syntax.

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:

Table 4.1: Flowchart Symbols


Symbol Name Meaning
Used to connect symbols and indicate the
Flowline flow of logic

Used to represent the beginning (Start) or


Terminal end (End) of a task

Used for Input and Output operations, such


as reading and displaying. The data to be
Input/Output
read or displayed are described inside.

Used for arithmetic and data manipulation


operations. The instructions are listed
Processing
inside the symbol.

Used for any logic or comparison


operations. Unlike input/output and
processing symbols, which have one entry
Decision and one exit flowline, the decision symbol
has one entry and two exits paths. The path
chosen depends on whether the answer to
a question is true or false.

82
Example: Draw a flowchart for a program that accepts two numbers and displays their
sum.

START

DISPLAY "Enter first number”

GET num1

DISPLAY "Enter second number”

GET num2

sum = num1 + 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:

i. Input: Gathering data from the user or an external source.

ii. Process: Manipulating the input data to perform calculations, apply logic,
or execute algorithms.

iii. Output: Presenting the results to the user or another system.

4.4.1 Components of the IPO Model


1. Input
• The input stage involves collecting data from the user or external sources (e.g.,
files, databases).
• In C++, input is commonly handled using:
o Standard input streams like cin.
o File handling mechanisms using ifstream.
o Other data sources, such as command-line arguments or network inputs.

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.

4.4.2 Designing Programs with the IPO Model


Using the IPO model ensures a systematic approach to program development. Below is
a step-by-step process:
1. Understand the problem: Clearly define the input, process, and output
requirements.
2. Identify the data: Determine the type and structure of the input and output.
3. Plan the logic: Design algorithms or logic for the processing stage.
4. Write the code: Implement the input, process, and output stages in C++.
5. Test the program: Verify that the program handles all cases correctly.

IPO Model Example:

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;

cout << "Enter the score for Subject 1: ";


cin >> score1;

cout << "Enter the score for Subject 2: ";


cin >> score2;

cout << "Enter the score for Subject 3: ";


cin >> score3;

// Process: Calculate the average


double average = (score1 + score2 + score3) / 3;

// Output: Display the average


cout << "The average grade is: " << average << endl;

return 0;
}

From the above code:


1. Input: The program collects three scores using cin.
2. Process: The scores are added and divided by 3 to compute the average.
3. Output: The result is displayed using cout.

Advantages of Using the IPO Model


1. Clarity:
- Separates different stages of the program, making the code easier to
understand.
2. Modularity:
- Facilitates reusability and maintainability by organizing code into distinct
stages.

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.

4.4.3 Applications of the IPO Model


The IPO (Input-Process-Output) model is a versatile framework applied across various
fields for analyzing, designing, and implementing systems. Below are key areas where
the IPO model is utilized:

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.

5.1.1 Types of program control structures


There are three main types of program control structures:
• Sequential/Consecutive program control structures
• Selection/Alternative program control structures
• Iteration/Repetition/Loop program control structures

Sequential/Consecutive program control structures


Statements are executed one after another in the order of their appearance in the source
code.
Execute first statement => then second statement => then third
statement, etc.
Every line of code is executed exactly once. Execution goes line by line from top to bottom

General pseudocode:
BEGIN
statement 1
statement 2
.
.
.
statement N
END

90
General Flowchart

START

Statement 1

Statement 2

• .
• .

Statement N

END

Figure 5.1: Sequential program control structures general flowchart

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.

Types of selection program control structures


There are two main forms of selection program control structures:
• IF Statement
• CASE/SWITCH Statement

5.2.1 The if Statement


The if statement can cause other statements to execute only under certain conditions.
If statement program control structure has the following sub forms:
a) IF
➢ Simple if statement
b) IF … ELSE
➢ Simple if-else Statement
c) IF … ELSEIF
➢ Nested if-else statement

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

Figure 5.2: Simple if Statement Program Control Structures General Flowchart

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.

b) The if-else Statement


The if-else statement will execute one set of statements when the if condition is
true, and another set when the condition is false. Used when there are two options
and only one is to be selected. When condition evaluates to TRUE, statements under
that condition are executed. When condition evaluates to FALSE, statements under
ELSE are executed.

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.

Example: A program to display PASS if grade scored is 50 or above otherwise FAIL.


#include<iostream>
using namespace std;
int main()
{
int grade;
cout << “Enter grade”;
cin >> grade;
if(grade >= 50)
{
Cout << “PASS”;
}
else
{
Cout << “FAIL”;
}
return 0;
}

96
General pseudocode:
BEGIN
IF condition THEN
statement(s)
ELSE
statement(s)
END IF
END

Example: A program to display PASS if grade scored is 50 or above otherwise FAIL.


BEGIN
USE VARIABLES: grade AS Integer
DISPLAY “Enter a grade”
GET grade
IF grade >= 50 THEN
DISPLAY “PASS”
ELSE
DISPLAY “FAIL”
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.

c) The if-else if statement


The if/else if statement is a chain of if statements. They perform their tests, one
after the other, until one of them is found to be true. Used when there are more than
two options and only one is to be selected. When first condition evaluates to TRUE,
statements under that condition are executed, otherwise the second condition is
checked. If first condition evaluates to FALSE and second condition is TRUE,
statements under second condition are executed. When all conditions evaluate to
FALSE, statements under ELSE are executed.

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

USE VARIABLES: grd AS Integer

DISPLAY “Enter a grade”

GET grd

IF grd>=0 and grd< 50 THEN

DISPLAY “FAIL”

ELSEIF(grd>=50 and grd<60 THEN

DISPLAY “PASS”

ELSEIF(grd>=60 and grd<75 THEN

DISPLAY “CREDIT”

ELSEIF(grd>=75 and grd<=100 THEN

DISPLAY “DISINCTION”

ELSE

DISPLAY “INVALID GRADE ENTERED”

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

...

False Condition True


N

Statement(s)
Statement(s)

Stop

Figure 5.4: if-else if statement program control structures general flowchart

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

5.2.2 CASE statement


CASE statement is also known as SWITCH statement program control structure. The
switch statement lets the value of a variable or expression determine where the program
will branch to. Is used when there are more than two options same as ELSEIF program
control structure. Is more compact than the IF … ELSE IF program control structure. It
does not work for a range of values for some programming languages such as C++.

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;

case label2: statement2;


break;
. . .
case labeln: statementn;
break;
default: statementd; //optional
}

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;
}

CASE statement general pseudocode:


BEGIN
CASE (case tag)
Case value 1:
statement(s)
Case value 2:
statement(s)
.
.
.
ELSE:
statement(s)
END CASE
END

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
?

Value1 Value2 Value3 ValueN

Statement(s)-1 Statement(s)-2 Statement(s)-3 Statement(s)-N

Stop

Figure 5.5: CASE statement program control structures general flowchart

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.

5.3 Loop/Iteration program control structures


Statement(s) are executed several times depending on the outcome of a condition.
Collection of statements that are executed repeated is called a loop body. Condition for
the loop can either be pre- condition or post-condition.

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.

The following are four forms of loops:


• While … do Loop
• Do … while Loop
• Repeat … until / Do … until Loop
• For Loop

5.3.1 The While … do Loop


While … do loop body repeats when the loop condition evaluates to TRUE and
terminates when condition evaluates to FALSE it is a pre-condition loop, hence if loop
condition is FALSE on the first test, the loop body is NOT executed AT ALL.

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

Figure 5.6: While … do Loop general flowchart

109
Activity 5.3a
Draw a flowchart for a program that display first ten positive integers (use while
… do)

The general form of a while statement is:


while (condition)
statement;

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.

Example: C++ program that display first ten positive integers


#include<iostream>
using namespace std;
int main()
{
int num;
num = 1;
while(num<=10)
{
cout<<num<<“ ”;
num = num+1;
}
return 0;
}

5.3.2 The Do … while Loop


Do … while loop body repeats when the loop condition evaluates to TRUE and
terminates when condition evaluates to FALSE. It is a post-condition loop; hence the loop
body is executed at least once even if the loop condition is FALSE on the first test. Can
be used in most situations as while…loop. It is an Indefinite loop

110
Do … while loop general pseudocode:
BEGIN
DO
Statement(s)
WHILE (Condition)
END

Example: A program to display first ten positive integers.


BEGIN
USE VARIABLES: num As Integer
num=1
DO
DIPLAY num, “ ”
COMPUTE num=num+1
WHILE (num<=10)
END

General Flowchart Start

Statement(s)

Condition True
False
?

Stop

Figure 5.7: Do … while loop general flowchart

111
Activity 5.3b
Draw a flowchart for a program that display first ten positive integers (use do …
while)

The general form of the do-while statement is:


do
statement
while (condition); // note the brackets!

Example: C++ program that display first ten positive integers


#include<iostream>
using namespace std;
int main()
{
int num;
num=1;
do
{
cout<<num<< “ ”;
num = num+1;
} while(num<=10);
return 0;
}

5.3.3 The Repeat … until Loop


Repeat … until loop body repeats when the loop condition evaluates to FALSE and
terminates when condition evaluates to TRUE. It is a post-condition loop; hence the loop
body is executed at least once even if the loop condition is TRUE on the first test. It is an
indefinite loop; it is just opposite of do … while loop. This form of loop program control
structure is not implemented in C++.

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

Figure 5.8: Repeat … until loop general flowchart

113
Activity 5.3c
Draw a flowchart for a program that display first ten positive integers (use
repeat … until)

5.3.4 The for Loop


For Loop body repeats when the loop condition evaluates to TRUE, terminates when
FALSE. It is a pre-condition loop, hence if loop condition is FALSE on the first test, the
loop body is NOT executed AT ALL. It is a definite loop because you can always tell how
many times the loop will occur. It’s an equivalent of while loop. Every for loop can be
converted to while loop, but not vice versa.

For loop general pseudocode:


BEGIN
FOR counter = startnum to endnum [STEP] DO
Statement(s)
END FOR
END

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.

Example: A program to display even number between 0 and 100.


BEGIN
USE VARIABLES: num As Integer
FOR num= 2 TO 100 [2]
DIPLAY num, “ “
END FOR
END

114
Flowchart is the same as for while ... Do loop

Start

Condition True
?

Statement(s)

Stop

Figure 5.9: For loop general flowchart

The general form of the for statement is:


for (initialization; test; update)
{
statement;
statement;
// Place as many statements
// here as necessary.
}

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.

i. Initialization expression: Used to initialize a counter to its starting value


ii. Test expression: It tests a condition
iii. Update expression: It executes at the end of each iteration. This is a statement that
increments/decrements the loop’s counter variable.

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;
}

Loop Control Statements in C++


Loop control statements are special statements used to change the normal execution
flow of loops. They help programmers control when a loop should stop or skip certain
iterations.

C++ provides two main loop control statements:


1. break
2. continue

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

cout << "i: " << i << endl;


}
return 0;
}

• 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

cout << "i: " << i << endl;


}
return 0;
}

• 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

Example of Nested Loop:


#include <iostream>
using namespace std;

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.

Advantages of modular programming


The following are some of the advantages of modular programming:
• Reduce size of program code by code reuse since repetitions of program lines is
avoided through calls.
• Easier to maintain program code since the errors might be easier to be identified
in specific modules.
• Speed up program coding since it is easier to share programming tasks in a team.
• Easier to understand the program due to readability as such simplifies
maintenance.
• Easier to upgrade the program since adding another module does not affect other
modules.

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

Pre-defined Functions in C++


Pre-defined functions (also called built-in functions or library functions) are
functions that are already written and provided by the C++ Standard Library.
Programmers do not need to declare or define these functions; they only need to
include the appropriate header file and call the function. These functions help
programmers avoid rewriting common tasks, making programming easier, faster, and
more efficient.
“Do not reinvent the wheel; use existing library functions.”
Importance of Pre-defined Functions
• Pre-defined functions are important because they:

o Save time and effort


o Reduce programming errors
o Improve program efficiency and reliability
o Provide tested and optimized solutions
o Increase programmer productivity

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>

Common Standard Header Files in C++


Header File Purpose
<iostream> Input and output functions
<cmath> Mathematical functions
<cstdlib> Utility functions (random, conversion)
<cstring> String handling (C-strings)
<cctype> Character handling
<algorithm> Sorting and searching
<ctime> Time and date functions
<iomanip> Output formatting
<fstream> File handling

Input/Output Functions (<iostream>)


• Used to interact with the user through keyboard and screen.
• Common Functions
o cin – Standard input
o cout – Standard output
o endl – New line
o getline(cin, str) – Reads a full line

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;
}

Mathematical Functions (<cmath>)


• Used for mathematical computations such as square root, power, and
trigonometry.
• Common Functions
o sqrt(x) – Square root
o pow(x, y) – x raised to power y
o abs(x) – Absolute value
o sin(x), cos(x), tan(x) – Trigonometric functions
o ceil(x) – Round up
o floor(x) – Round down

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;
}

Time Functions (<ctime>)


• Used to get and manipulate date and time information.
• Common Functions:
o time(0) – Current time in seconds
o clock() – Processor time

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;
}

Utility Functions (<cstdlib>)


• Used for random numbers, conversions, and memory operations.
• Common Functions:
o rand() – Generates random number
o srand(seed) – Seeds random generator
o atoi(str) – Converts string to int
o atof(str) – Converts string to float

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;
}

String Handling Functions (<cstring>)


• Used to manipulate C-style strings (character arrays).
• Common Functions:
o strlen(str) – Length of string

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;
}

Character Handling Functions (<cctype>)


• Used to classify and convert characters.
• Common Functions:
o isupper(ch) – Checks uppercase
o islower(ch) – Checks lowercase
o isdigit(ch) – Checks digit
o isspace(ch) – Checks whitespace
o toupper(ch) – Convert to uppercase
o tolower(ch) – Convert to lowercase

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;
}

Formatting Functions (<iomanip>)


• Used to control how output is displayed.
• Common Functions:
o setw(n) – Sets field width
o setprecision(n) – Sets decimal precision
o fixed – Fixed-point notation

Example Program:
#include <iostream>
#include <iomanip>
using namespace std;

int main() {
double num = 123.456789;

cout << fixed << setprecision(2);


cout << "Formatted number: " << num << endl;

return 0;
}

File Handling Functions (<fstream>)


• Used to read from and write to files.
• Common Classes:
o ifstream – Input file stream
o ofstream – Output file stream
o fstream – Input and output
• Common Functions:
• open() – Open file
• close() – Close file

127
Example Program:
#include <iostream>
#include <fstream>
using namespace std;

int main() {
ofstream file("[Link]");
file << "Hello, file!";
[Link]();

cout << "File written successfully!" << endl;


return 0;
}

Sorting and Searching Functions (<algorithm>)


• Used for sorting and searching data in arrays and containers.
• Common Functions:
o sort(begin, end) – Sort elements
o reverse(begin, end) – Reverse elements
o find(begin, end, value) – Search value

Example:
#include <iostream>
#include <algorithm>
using namespace std;

int main() {
int arr[] = {5, 2, 9, 1};
sort(arr, arr + 4);

for(int i = 0; i < 4; i++)


cout << arr[i] << " ";

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.

6.2.1 Defining a function


When creating a function, you must write its definition. All function definitions have the
following parts:
i. Name: Every function must have a name. In general, the same rules that apply to
variable names also apply to function names
ii. Parameter list: The program module that calls a function can send data to it. The
parameter list is the list of variables that hold the values being passed to the
function. If no values are being passed to the function, its parameter list is empty.
iii. Body: The body of a function is the set of statements that carry out the task the
function is performing. These statements are enclosed in a set of braces.
iv. Return type: A function can send a value back to the program module that called
it. The return type is the data type of the value being sent back.

General syntax for function definition:


type function_name(parameters)
{
//statements here
return variable; // or return value;
}

Parameters are in the form of:


type variable1, type variable2, …, type variable
Some functions may have no parameters.
First line: type function_name(parameters) is called function header.
• type before function name is the type of value the function will return
• Parameters are variables that receive values from the function caller

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.

Example: A function to add two numbers can be defined as:


int sum(int Num1, int Num2)
{
int result;
result = Num1 + Num2;
return result;//note that result data type is the same as function’s data type

Declaring a Function – Prototype


A function is declared just before the main(). Function declaration is also called
prototype. Function declaration is the same as the function header but with semi colon
(;) at the end.

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.

Where to place a function definition in a program


Your function definition can be written in one of the following places:
i. At the end of main() function. This requires the function to be declared just before
the main().
ii. Before the main() function. This does not require function declaration. Therefore,
do not declare this function.
iii. In a separate file called header file. Function definitions are written in a file with .h
extension. The file is then included using #include.

Table 5.1: Where To Place a Function Definition in a Program


//At the end of main(): //Before main():
#include<iostream> #include<iostream>
//declaration //function definition
int multiply(int a, int b); int multiply(int a, int b)
//main function {
int main() return a*b;
{ }
//statements here; //main function
} int main()
//function definition {
int multiply(int a, int b) //statements here
{ }
return a*b;
}

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.

General syntax to call a function:


variable = function_name(arguments);

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).

From general syntax:


• The data type of the variable (left hand side) should match that of the function
return type
• List of arguments should generally match the list of function’s parameters
• Arguments and parameters should be in a correct sequence and in a matching
data type.

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

int getSum( int a, int b ) //a and b are parameters


{
return a+b; //return a result of data type int
}

Stack Memory and Function Call in C++

What is Stack Memory?


The stack is a special region of computer memory used to store temporary data created
by functions, including local variables, function parameters, and return [Link]
memory is automatically managed by the CPU and compiler, meaning programmers
do not manually allocate or free stack memory.

Characteristics of Stack Memory


1. LIFO Principle (Last In, First Out)
The stack follows the LIFO (Last In, First Out) rule, meaning:
• The last item added to the stack is the first one removed.
• Similar to a stack of books: you remove the top book first.

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

Push and Pop Operations


Push
• When a function creates variables, they are pushed onto the stack.
Pop
• When a function finishes, its variables are popped (freed) from the stack.
• Freed stack memory becomes available for other function calls.

Stack and Function Calls


• Whenever a program calls a function, information about the function call is
stored in the stack. This information is called a stack frame or activation
record.
• A stack frame contains:
o Local variables of the function
o Parameters passed to the function
o Return address (where to go after function ends)
o Saved registers and execution state

Example of Function Call Chain


Assume we have three functions:
main() → func1() → func2()

134
Step-by-Step Execution Flow
Step 1: main() Starts
• main() is executed first.
• A stack frame for main() is created.

Step 2: main() Calls func1()


• Control is transferred to func1().
• The status of main() (return address, variables) is stored on the stack.
• A new stack frame for func1() is pushed.

Step 3: func1() Calls func2()


• Control is transferred to func2().
• The status of func1() is stored on the stack.
• A stack frame for func2() is pushed.

Step 4: func2() Finishes


• func2() completes execution.
• Its stack frame is popped from the stack.
• Control returns to func1() using the return address stored in the stack.

Step 5: func1() Finishes


• func1() completes execution.
• Its stack frame is popped.
• Control returns to main().

Step 6: main() Finishes


• main() ends, and its stack frame is removed.
• Program terminates.

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;
}

• Variable a is stored in main() stack frame. Variable b is stored in func1() stack


frame. Variable c is stored in func2() stack frame. When each function ends, its
variables are removed automatically.

Advantages of Stack Memory


• Fast memory allocation and deallocation
• Automatically managed by system
• Efficient for function calls and local variables

Limitations of Stack Memory


• Limited size (can cause stack overflow)
• Variables exist only during function execution
• Not suitable for large data structures (heap is better for that)

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.

General syntax for procedure definition:


void procedure_name(parameters)// Note void here in place of type
{
//statements here;
// no return statement;
}
Parameters are in the form of:
type variable1, type variable2, …, type variableN
Some procedures may have no parameters

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

General syntax to call a procedure:


procedure_name(arguments); //no assignment statement here (no =)

Example: A program to display massage from two functions: main and


displayMessage.
#include <iostream>
using namespace std;
void displayMessage(); //Declaring a procedure
int main()
{
cout << "Hello from main function.\n";
displayMessage(); // Call displayMessage procedure
return 0;
}

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

Figure 6.2: Value parameters and memory location


Passing arguments by value has the following disadvantages:
• The original value is not modified when the passed value is changed in a function.
Sometimes you may need the original value to be changed as well.
• When data transferred is too big, a lot of memory is consumed and more time is
taken to complete copying the data.

Solution is to use either reference parameters i.e., Pass arguments by reference or


Pointer parameters.

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.

Figure 6.3: Reference Parameters

140
Defining a function parameter as reference parameter is made by placing an ampersand
sign (&) after the data type.
Function definition:

int func1(int& a) // & indicates that a is reference parameter


{
//statements here;
}

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;
}

int doubleNum (int &number)


{
return number * 2;
}

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?

6.2.4 The return Statement


The return statement causes a function to end immediately. When the last statement in a
function has finished executing, the function terminates. The program returns to the
module that called it and continues executing from the point immediately following the
function call. It is possible, however, to force a function to return to where it was called
from before its last statement has been executed. This can be done with the return
statement.

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;
}

void divide(double num1, double num2)


{
if (num2 == 0.0)
{
cout << "Sorry, I cannot divide by zero.\n";
return;
}
cout << "The quotient is " << (num1 / num2) << endl;
}

Activity 6.2e
How many return values may a function have?

6.2.5 Overloaded Functions


Sometimes you will create two or more functions that perform the same operation, but
use a different set of parameters, or parameters of different data types. Two different
functions can have the same name provided they have different function signatures
(headers). Function signatures (headers) are said to be different if either they have
different number of arguments or different types in their arguments. These functions
are known as overloaded functions. The C++ compiler selects the proper function to
call by examining the number, types and order of the arguments in the call.

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;
}

int getSum(int a, int b)


{
return a+b;
}

int getSum(int a, int b, int c)


{
return a+b+c;
}

double getSum(double a, double b)


{
return a+b;
}

Activity 6.2f
Is it required that overloaded functions have different return types, different
parameter lists, or both?

6.2.6 Inline Functions


Implementing a program as a set of functions is good but function calls involve execution
time overhead. C++ provides inline functions to help reduce function call overhead
especially for small functions. Placing the qualifier inline before a function’s return type
in the function definition directs the compiler to generate a copy of the function’s body
code in place (when appropriate) to avoid a function call.

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;
}

Iterative and Recursive Functions

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

• Iteration is commonly used when the number of repetitions is known or can be


controlled by a condition.

Characteristics of Iteration
• Uses loop statements
• Faster execution in many cases
• Does not use function calls repeatedly
• Easier to understand for beginners

Example: Iterative Function to Calculate Sum of First n Integers


int sum(int n) {
int total = 0;
for(int i = 1; i <= n; i++) {
total = total + i;
}
return total;
}

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

Base Case and Recursive Case


1. Base Case
• The condition that stops the recursion.
• Prevents infinite function calls.

2. Recursive Case
• The part where the function calls itself.

Example: Recursive Function to Calculate Sum of First n Integers


int sum(int n) {
if(n == 1) { // Base case
return 1;
}
else {
return n + sum(n - 1); // Recursive call
}
}

• If n == 1, the function returns 1 (stopping condition). Otherwise, it returns n +


sum(n-1). The function keeps calling itself until n becomes 1.

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();
}

A function is said to be recursive if it calls itself. Used to solve a self-repeating problem.


It is useful for tasks such as some sorting methods or to calculate the factorial of a
number. There’s no way to stop the recursive calls. This function is like an infinite loop
because there is no code to stop it from repeating. A recursive function must have a way
of controlling the number of recursive calls. Recursive functions work by breaking a
complex problem down into subproblems of the same type. This breaking down process
stops when it reaches a base case.

Example: Factorial of a number n (denoted n!) is calculated as:


n! = n * (n-1) * (n-2) * (n-3) ... * 1

#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?

6.2.8 Creating Header Files


A header file is a file that contains function declarations, class definitions, constants,
and macros that can be shared among multiple C++ source files. Header files help in
modular programming, where a large program is divided into smaller, manageable
parts.

File Extension
• Header files are saved with the .h or .hpp extension.
• Examples:
student.h, mathutils.h, main.h

Importance of Header Files


Header files are important because they:
• Allow code reuse in multiple programs
• Help organize large programs into modules
• Enable team collaboration (different programmers work on different modules)
• Improve readability and maintainability of programs
• Reduce duplication of code

148
Modular Programming in C++
Modular programming means dividing a program into separate files or modules.

Typical C++ Project Structure


1. Header Files (.h)
o Contain function declarations and class definitions
2. Implementation Files (.cpp)
o Contain function and class implementations
3. Main File ([Link])
o Uses the functions and classes defined in other modules

Creating a Project in Dev-C++


Step 1: Create a New Project
o Click File → New → Project…
Step 2: Choose Project Type
o Select Console Application (for console programs)
Step 3: Set Project Name and Location
o Enter project name
o Choose where to save project files
Step 4: Add Files
o Add .h and .cpp files to the project
o Write declarations in .h and definitions in .cpp

Including Header Files in a Program


• To use a header file, we use the #include directive.
• Use double quotes (" ") for user-created header files
o Use angle brackets (< >) for standard libraries

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

int add(int a, int b);

#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;
}

Advantages of Using Header Files


• Encourages modular programming
• Makes large programs easy to manage
• Allows team members to work independently
• Promotes code reuse and standardization
• Improves compilation efficiency

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

6.3 Variable Scope


Identifiers are declared in a function heading, within a block, or outside a block. A question
naturally arises: Are you allowed to access any identifier anywhere in the program? The
answer is no. You must follow certain rules to access an identifier. The scope of an
identifier refers to where in the program an identifier is accessible (visible). Recall that an
identifier is the name of something in C++, such as a variable or function name. There
are two main types of variables in a program:
• Local variable
• Global variable

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.

Example: Local variables


#include <iostream>
using namespace std;
void anotherFunction(); // Function prototype
int main()
{
int num = 1; // Local variable
cout << "In main, num is " << num << endl;
anotherFunction(); //function call
cout << "Back in main, num is still " << num << endl;
return 0;
}
void anotherFunction()
{
int num = 20; // Local variable
cout << "In anotherFunction, num is " << num << endl;
}

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.

6.3.2 Global Variables


A global variable is defined outside all functions and is accessible to all functions in its
scope. A global variable is any variable defined outside all the functions in a program,
including main. The scope of a global variable is the portion of the program from the
variable definition to the end of the entire program. This means that a global variable can
be accessed by all functions that are defined after the global variable is defined. They are
created when the program starts execution and ceases to exist when the program has
finished execution.

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;
}

Scope Resolution Operator (::)


The scope resolution operator (::) is used to access something outside the current
scope (like a global variable, class member, or namespace).

Accessing Global Variables


Sometimes a local variable hides a global variable with the same name.

Example 1:

#include <iostream>
using namespace std;

int x = 100; // Global variable

int main() {

154
int x = 50; // Local variable

cout << "Local x = " << x << endl;


cout << "Global x = " << ::x << endl; // Access global x

return 0;
}

Example with Function:


#include <iostream>
using namespace std;

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
}

Static Variables in C++


• A static variable keeps its value even after the function ends.
o Normal local variables are destroyed after function execution.
o Static variables remember their value.

Key Characteristics of Static Variables


• Persistent Value
o Value is not lost between function calls
• Lifetime
o Exists throughout the program execution
• Scope
o Visible only inside the function/block where declared

155
• Memory
o Stored in data segment (not stack)
• Default Initialization
o Automatically initialized to 0 if not specified

Syntax of Static Variable


static dataType variableName;

Example:

static int count;

Static Variable Example (Function Call Counter)


#include <iostream>
using namespace std;

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;
}

When to Use Static Variables


Use static variables when you want to:
• Count how many times a function is called
• Track program state
• Store persistent data without global variables
• Implement counters and flags

156
Activity 6.3
What are the differences between a local variable and a global variable?

6.4 Memory Management


Memory management incorporates all processes and methodologies for the effective use,
allocation, monitoring and management of computer memory. Memory management
allows an underlying computer or operating system (OS) to dynamically distribute
memory across all running processes, while ensuring optimal performance. Memory
management deals with the management of a computer’s physical memory or Random-
Access Memory (RAM). Memory management is usually performed and managed by the
host operating system.

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

An executable program generated by a compiler will have the following:


i. Code segment or text segment:
• Code segment contains the code executable or code binary
ii. Data segment:
• Data segment is sub divided into two parts
o Initialized data segment: All the global, static and constant
data are stored in the data segment
o Uninitialized data segment: All the uninitialized
iii. Heap
iv. Stack

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.

6.4.2 Stack segment


It's a special region of your computer's memory that stores temporary variables created
by each function (including the main() function). The stack is a "LIFO" (last in, first out)
data structure, that is managed and optimized by the CPU quite closely. Every time a
function declares a new variable, it is "pushed" onto the stack. Then every time a function
exits, all of the variables pushed onto the stack by that function, are freed (that is to say,
they are deleted). Once a stack variable is freed, that region of memory becomes
available for other stack variables.

Advantage of using the stack


The following are advantages of using stack memory:
• Memory is managed for you.
• Don't have to allocate memory by hand, or free it.
• Reading from and writing to stack variables is very fast (the CPU organizes
stack memory efficiently)

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.

7.1. Introduction to Data Structures

7.1.1. What is a Data Structure?


In the world of computer science and programming, data is at the core of everything.
Whether it's numbers, text, images, or complex objects, programs need to store and
manage data efficiently to perform their tasks effectively. This is where the concept of a
data structure becomes fundamental.

A data structure is essentially a way of organizing and storing data in a computer so


that it can be accessed and modified efficiently. It's not just about putting data
somewhere; it's about arranging it in a specific manner that facilitates particular
operations. Think of it like organizing your books on a shelf: you could stack them
randomly, or you could arrange them alphabetically, by genre, or by size. Each method
of organization makes certain tasks (like finding a specific book) easier or harder.

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.

Data structures are broadly divided into two main categories:


i. Primitive Data Structures
ii. Non-Primitive Data Structures

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;

• float (floating-point number): Used to store numbers with a decimal point,


representing single-precision floating-point values (e.g., 3.14, -0.5, 123.45f). They
are suitable for calculations requiring decimal precision.
o Example: float temperature = 25.7f;

• 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

[Link] Linear Data Structures


In linear data structures, data elements are organized sequentially, one after another.
Each element is connected to its previous and next one, forming a single, continuous
sequence. This makes them intuitive for representing lists or sequences of items.
Examples of linear data structures include:
i. Array:
o A collection of elements of the same data type stored at contiguous
(adjacent) memory locations.
o Elements are accessed using an index (e.g., array[0], array[1]).
o Arrays have a fixed size defined at the time of creation in many languages
(like C++'s built-in arrays), though dynamic arrays (like std::vector in
C++) can resize.
o Analogy: A row of lockers, each with a number, where you can directly go to
any locker by its number.
o Operations: Accessing by index (O(1)), insertion/deletion at ends (O(1) for
dynamic arrays), insertion/deletion in middle (O(n)).

ii. Linked List:


o A collection of elements (called nodes) where each node contains two parts:
the data and a pointer (or reference) to the next node in the sequence.

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.

Examples of non-linear data structures include:


i. Tree:
o A hierarchical data structure where data is organized in parent-child
relationships.
o It consists of nodes connected by edges. The topmost node is called the root.
Each node can have zero or more child nodes.
o Trees are widely used to represent hierarchical data like file systems,
organizational charts, or XML/JSON structures.
o Analogy: A family tree or an inverted tree where the root is at the top and
branches extend downwards.

ii. Binary Tree:


o A special type of tree where each node has at most two children, typically
referred to as the "left child" and the "right child."
o Binary trees are fundamental and serve as the basis for many other data
structures and algorithms.

iii. Binary Search Tree (BST):


o A specific type of binary tree that maintains a sorted order among its elements.
o For every node, all values in its left subtree are less than the node's value,
and all values in its right subtree are greater than the node's value.
o This property makes BSTs highly efficient for searching, insertion, and
deletion operations (average O(log n)).

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.

[Link]. Hash-Based Data Structures


Hash-based data structures are designed for extremely fast data access, typically
achieving an average time complexity of O(1) (constant time) for insertion, deletion, and
retrieval operations. They achieve this efficiency by using a hash function.
• A hash function takes a key as input and computes an index (or address) in a data
storage array (often called a hash table or hash map). This index indicates where
the corresponding value should be stored or retrieved.
• The goal of a good hash function is to distribute keys evenly across the array,
minimizing "collisions" (where different keys map to the same index).

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.

7.1.4. Importance and Applications of Data Structures


Understanding data structures is crucial for any aspiring programmer or computer
scientist because:
• Efficiency: Choosing the right data structure can drastically improve the
performance (speed and memory usage) of your programs. For example, searching
for an element in a sorted array is much faster than in an unsorted one, and a hash
table offers near-instant lookups compared to a linked list.

• Problem Solving: Data structures provide a systematic way to organize and


manage data, which is often the first step in solving complex computational
problems. They are the tools you use to structure information.

• 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).

• Foundation of Software: Almost all complex software systems, from operating


systems and databases to web browsers and artificial intelligence, are built upon
sophisticated uses of various data structures.

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

Element First index Last index


(value)
Figure 7.1: Graphical Representation of an Array of n Numbers

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.

7.2.1. Operations of an array


The three basic operations of an array are described as follows:
i. create() array: This operation creates an empty, new array. Whenever
a new array is created, it is initially empty.

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.

iii. store(array, index, value) array: This operation is used to store a


value in the array at a specified index position giving the updated array as an
output.

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 */

Consider the following array definition:


int hours[6];

Element 0 Element 1 Element 2 Element 3 Element 4 Element 5

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};

7.2.3. Assigning Values to an Array


You can assign values to an array by initializing at declaration. Array elements may also
have information read into them using the cin object and have their values displayed
with the cout object, just like regular variables, as long as it is done one element at a
time.

General syntax for assigning values to array of size n:

array_name[0] = value1; /* This assigns value1 to array at 1st position


(index =0) */
array_name[1] = value2; /* This assigns value2 to array at 2nd position
(index =1) */
.
.
.
array_name[n-1]=valuen;/*This assigns valuen to array at nth position
(index =n-1)*/

Assigning five grades of a student will be:


int grades[5]; // first declare the array
grades[0] = 40;
grades[1] = 52;
grades[2] = 67;
grades[3] = 33;
grades[4] = 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.

7.2.4. Displaying values of an array


General syntax to display values of array:
cout << array_name[index];

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?

7.3. Two-Dimensional Arrays


Two-dimensional array is like several identical arrays put together. It is useful for storing
multiple sets of data. An array is useful for storing and working with a set of data.
Sometimes, though, it’s necessary to work with multiple sets of data. For example, in a
grade-averaging program a teacher might record all of one student’s test scores in an
array of doubles. If the teacher has 30 students, that means 30 arrays of doubles will
be needed to record the scores for the entire class. Instead of defining 30 individual
arrays, however, it would be better to define a two-dimensional array.

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

Figure 7.3: 2D array of 3 students with 5 grades

7.3.1. Declaring Two-Dimensional Array


To define a two-dimensional array, two size declarators are required: the first one is for
the number of rows and the second one is for the number of columns.

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},
};

7.3.2. Assigning Values Two-Dimensional Array


The general syntax for assigning values to 2D array of size m x n:
array_name[0][0] = value01; /* This assigns value01 to array
at 1st row and 1st column */

array_name[0][1] = value02; /* This assigns value02 to array


at 1st row and 2nd column */
. . .
array_name[0][n] = value0n; /* This assigns value0n to
array at 1st row and nth column */

array_name[1][0] = value11; /* This assigns value11 to


array at 2nd row and 1st column */

array_name[1][1] = value12; /* This assigns value12 to array


at 2nd row and 2nd column */
...
array_name[1][n] = value1n; /*This assigns value1n to array
at 2nd row and nth column */
.
.
.
array_name[m-1][n-1] = valuemn; /* This assigns valuemn to
array at mth row and nth column */

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;

7.3.3. Display Values Two-Dimensional Array


Displaying values of 2D array is as below:
General Syntax:
cout << array_name[i-index][j-index];
Example:
int grades[3][5] = {
{45, 40, 52, 67, 33},
{48, 75, 57, 64, 88},
{53, 46, 38, 78, 66},
};

cout << grades[0][0];//displays 45 (element at row1 column1)


cout << grades[2][3];//displays 78 (element at row3 column4)

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.

7.4. Manipulating Array Contents


7.4.1. Processing array elements
Processing array elements is no different than processing other variables. For example,
the following statement multiplies hours[3] by the variable rate:

pay = hours[3] * rate;

[Link]. Copying one array to another


To copy the contents of one array to another, you must assign each element of the first
array, one at a time, to the corresponding element of the second array.

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.

[Link]. Summing All the Elements of a Two-Dimensional Array


To sum all the elements of a two-dimensional array, you can use a pair of nested loops
to add the contents of each element to an accumulator.

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;

[Link]. Finding the Highest and Lowest Values in a Numeric Array


The algorithms for finding the highest and lowest values in an array are very similar.
Assume that the following statements appear in a program.
const int SIZE = 10;
int numbers[SIZE] = {15, 6, 3, 11, 22, 4, 0, 1, 9, 12};

The code to find the highest value in the array is as follows.


int count;
int highest;
highest = numbers[0];
for (count = 1; count < SIZE; count++)
{
if (numbers[count] > highest)
highest = numbers[count];
}

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];
}

[Link]. Inserting an Element into an Array


The insert() operation inserts an element at a specified location into the array. A lot of
data movement is involved in the insert() operation. To insert an element at the ith
position in an array of size N, all the elements originally at positions i, i + 1, i + 2,
...,N – 1 will be shifted to i + 1, i + 2, i + 3, ..., N, respectively so that
each element gets shifted to the right by one position. All the data shifting must be
performed before the actual insertion. Moreover, before insertion, room must be created
for the element at the ith position, and then the element is placed there.

Data shifting can be performed using the following function:


void ArrayInsert(int Location, int Element)
{
int i;
if(Size >= MaxSize)
{
cout << "Sorry, Array Overflow";
return;
}

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;
}

[Link]. Deleting an Element


The delete() operation removes the specified element from the array. Deletion of an
element is achieved by overwriting the element. After one deletion operation, one location
becomes empty, so all the elements should be shifted by one position after the deleted
element to fill in the empty location of the deleted element. In short, deletion can be
handled by simply overwriting the specified location.
Deletion can be performed using the following function:

void ArrayDelete(int Location)


{
int i;
for(i = Location; i < Size; i++)
{
A[i - 1] = A[i];//shifting elements to the left by 1 position
}
A[Size - 1] = 0;//Store 0 at the last location to mark it empty
Size = Size - 1;
}

7.4.2. Passing Arrays to Functions


To pass an array as an argument to a function, simply pass the name of the array. When
a single element of an array is passed to a function, it is handled like any other variable.
To pass an array argument to a function: Specify the name of the array without brackets
and the array size.
int stdMarks[50];
void DisplayMarks(stdMarks, 50);

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;

void display(int marks[5]); // Function prototype

int main()
{
int marks[5]={88,76,90,62,69};
display(marks); //function call
return 0;
}

void display(int m[5])


{
cout<<“Displaying Marks:”<<endl;
for(int i=0;i<5;i++)
{
cout<<“Student” <<i+1<<“:”<<m[i]<<endl;
}
}

7.4.3. Advantages and Disadvantages of arrays


We have looked an array as an abstract data type and also its implementation. We have
also studied and analyzed a few applications that use an array as a data structure. Now
what are the characteristics, advantages and disadvantages of an array as a data
structure?

[Link]. Characteristics of arrays


The characteristics of an array are as follows:
• An array is a finite ordered collection of homogeneous data elements.
• In an array, successive elements are stored at a fixed distance apart.
• An array is defined as a set of pairs; index and value.
• An array allows direct access to any element.

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.

[Link]. Advantages of arrays


The various merits of the array as a data structure are as follows:
• Array can store a large number of values with single name.
• Arrays permit efficient random access in constant time
• Arrays are most appropriate for storing a fixed amount of data and also for high
frequency of data retrievals as data can be accessed directly.
• Arrays are among the most compact data structures; if we store 100 integers in an
array, it takes only as much space as the 100 integers, and no more (unlike a
linked list in which each data element has an additional link field).
• Arrays are well known in applications such as searching, hash tables, matrix
operations, and sorting.
• Wherever there is a direct mapping between the elements and their position, such
as an ordered list, arrays are the most suitable data structures.
• Arrays are useful to implement other data structures like linked lists, stacks,
queues, trees etc.

[Link]. Disadvantages of arrays


Some of the disadvantages of arrays are as follows:
• Arrays provide static memory management. Hence, during execution, the size can
neither be grown nor shrunk.
• They keep data (values) of the same data type.
• There is a solution to handle the problem, that is, to declare the array of some
arbitrarily maximum size. This leads to two other problems:
➢ In future, if the user still needs to exceed this limit, it is not possible
➢ Higher the maximum, more memory wastage - poor utilization of space
• An array is inefficient when often data is inserted or deleted as insertion or deletion
of an element in an array needs a lot of data movement.

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.

[Link]. Search Techniques


Depending on the way data is scanned for searching a particular record, the search
techniques are categorized as follows:
• Sequential search
• Binary search
• Fibonacci search
• Hashed search
• Index sequential search
The performance of a searching algorithm can be computed by counting the number of
comparisons to find a given value.

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.

[Link]. Types of Sorting


Sorting algorithms are divided into two categories:
• Internal sorting
• External sorting
If all the records to be sorted are kept internally in the main memory, they can be sorted
using an internal sort. However, if there are a large number of records to be sorted, they
must be kept in external files on auxiliary storage. They have to be sorted using external
sort.

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.

3. Sort Efficiency: - Sort efficiency is a measure of the relative efficiency of a sort. It


is usually an estimate of the number of comparisons and data movement required
to sort the data.

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

8.2.1. Sequential Search


The Sequential search is a very simple algorithm. Sometimes called a linear search. A
sequential search begins with the first available record and proceeds to the next available
record repeatedly until we find the target key or conclude that it is not found. The linear
search can be applied on sorted or unsorted linear data structure

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

int LinSearch(int x[ ], int n, int item)


{
for(int i=0;i<n;i++)
{
if(x[i]==item) return true;
else return false;
}
return false;
}

The function LinSearch() is defined with three parameters


int LinSearch(int x[ ], int n, int item)
1. The element to be searched
2. The array X where the element is to be searched
3. The total number of elements in the array.

The function LinSearch() returns the location of the element if found or returns -1
if the element is not found.

[Link]. Advantages of Sequential Search


The following are some of the advantages of linear search:
1. A simple and easy method
2. Efficient for small lists
3. Suitable for storage structures which do not support direct access to data, for
example, magnetic tape, linked list, etc.
4. The elements in the list can be in any order. The linear search can be applied
on sorted or unsorted linear data structure
5. Best case is one comparison, worst case is n comparisons, and average case
is (n + 1)/2 comparisons.

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.

Example 1: Linear search without using a function.


#include<iostream>
using namespace std;
int main()
{
int size, key, i;
int array[size];
cout<<"Enter the size of the array: ";
cin>>size;
//taking input in an array
for(int j=0;j<size;j++)
{
cout<<"Enter "<<j<<" Element";
cin>>array[j];
}
//your Entered array is
for(int a=0;a<size;a++)
{
cout<<"array["<<a<<"]= ";
cout<<array[a]<<endl;
}
cout<<"Enter key to search in the array: ";
cin>>key;
for (i=0;i<size;i++)
{
if (key = = array[i])
{
cout<<"Key found at index number:"<<i<<endl; break;
}
}
if (i!=size)
{
cout<<"key found at index: "<<i;
}
else
{
cout<<"KEY NOT FOUND IN ARRAY";
}
return 0;
}

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;

for (i = 0; i < size; i++)


cin >> arr_search[i];
cout << "\nYour Data :";

for (i = 0; i < size; i++)


{
cout << "\t" << arr_search[i];
}

cout << "\nEnter Element to Search: ";


cin>>element;

linear_search(arr_search, element);
}

//Linear Search Function


void linear_search(int fn_arr[], int element)
{
int i;
//for : Check elements one by one - Linear
for (i = 0; i < size; i++)
{
//If for Check element found or not
if (fn_arr[i] == element)
{
cout << "\nLinear Search : Element : " << element <<
" : Found : Position : " << i + 1 << ".\n";
break;
}
}
if (i == size)
cout << "\nSearch Element: " << element << ": Not Found \n";
}

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.

Binary Search: middle element


𝐥𝐞𝐟𝐭+𝐫𝐢𝐠𝐡𝐭
mid =
𝟐

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;
}

[Link]. Advantages of Binary Search


The following are some of the advantages of Binary search:
1. Suitable for sorted data
2. Efficient for large lists
3. Suitable for storage structure that supports direct access to data

[Link]. Disadvantages of Binary Search


The following are some of the disadvantages of Binary search:
1. Not usable for unsorted data
2. Not usable for storage structure that do not support direct access to data, for
example, magnetic tape and linked list
3. Inefficient for small lists

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";

for (i=0; i<n;i++)


{
cin>>arr[i];
}
cout<<"Enter a number to find: ";
cin>>search;

first = 0;
last = n-1;
middle = (first + last)/2;

while(first <= last)


{
if(arr[middle] < search)
{
First = middle + 1;
}
else if(arr[middle]= = search)
{
cout<<search<<" Found at location "<<middle+1<<"\n";
break;
}
else
{
Last = middle - 1;
}
Middle = (first + last)/2;
}
if(first > last)
{
cout<<"Not found! "<<search<<"is not present in the list.";
}
return 0;
}

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;

for (i = 0; i < size; i++)


{
cin >> arr_search[i];
}
cout << "\nYour Elements are:";

for (i = 0; i < size; i++)


{
cout << "\t" << arr_search[i];
}

cout << "\nEnter Element to Search: ";


cin>>element;
binary_search(arr_search, element);
}

void binary_search(int fn_arr[], int element)


{
int f = 0, r = size, mid;
while (f <= r)
{
mid = (f + r) / 2;
if (fn_arr[mid] = = element)
{
cout << "\nSearch Element: " << element << ": Found
: Position: " << mid + 1 << ".\n";
break;
}
else if (fn_arr[mid] < element)
f = mid + 1;
else
r = mid - 1;
}
if (f > r)
cout<<"\nSearch Element:"<< element<< ": Not Found \n";
}

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?

8.3. Sorting Algorithms


Sorting algorithms are used to arrange data into some order. To sort the data in an array,
the programmer must use an appropriate sorting algorithm. A sorting algorithm is a
technique for scanning through an array and rearranging its contents in some specific
order. The three basic sorting algorithms are the following:
• Selection Sort
• Bubble Sort
• Insertion Sort

8.3.1. Selection Sort


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. Because the
elements are added to the sorted sequence in order, they are always added at one end.

In this method, we sort a set of unsorted elements in two steps:


• In the first step, find the smallest element in the structure
• In the second step, swap the smallest element with the element at the first position
• Then, find the next smallest element and swap with the element at the second
position
• Repeat these steps until all elements get arranged at proper positions

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

Selection sort algorithm:


void SelectionSort(int A[], int n)
{
int i, j;
int minpos, temp;
for(i = 0; i < n − 1; i++)
{
minpos = i;
for(j = i + 1; j < n; j++)
//find the position of min element as minpos from i + 1 to n − 1
{
if(A[j] < A[minpos])
minpos = j;
}
if(minpos != i)
{
//swap the ith element and minpos element
temp = A[i];
A[i] = A[minpos];
A[minpos] = temp;
}
}
}

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;
}

// Sort arr[ ] of size n using Selection Sort.


void SelectionSort (int arr[], int n)
{
int i, j;
for (i = 0; i < n; ++i)
{
for (j = i+1; j < n; ++j)
{
//Comparing consecutive data and switching values if value at i > j.
if (arr[i] > arr[j])
{
arr[i] = arr[i]+arr[j];
arr[j] = arr[i]-arr[j];
arr[i] = arr[i]-arr[j];
}
}
// Value at i will be minimum of all the values above this index.
}
}

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

What will be results of bubble sort for each pass?

Table 8.2: Bubble Sort


Unsorted 76 67 36 55 23 14 6
Pass 1 Step 1 67 76 36 55 23 14 6
Step 2 67 36 76 55 23 14 6
Step 3 67 36 55 76 23 14 6
Step 4 67 36 55 23 76 14 6
Step 5 67 36 55 23 14 76 6
Step 6 67 36 55 23 14 6 76
Pass 2 Step 1 36 67 55 23 14 6 76
Step 2 36 55 67 23 14 6 76
Step 3 36 55 23 67 14 6 76
Step 4 36 55 23 14 67 6 76
Step 5 36 55 23 14 6 67 76
Pass 3 Step 1 36 55 23 14 6 67 76
Step 2 36 23 55 14 6 67 76
Step 3 36 23 14 55 6 67 76

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

Bubble Sort Algorithm


Step 1: Let A be the array to be sorted
Step 2: for i = 1 to n − 1
for j = 0 to n − i
begin
if A[j] > A[j+1] then
Swap A[j] with A[j + 1] as follows
temp = A[j]
A[j] = A[j + 1]
A[j + 1] = temp
end
end

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;
}

// Sort arr[ ] of size n using Bubble Sort.


void BubbleSort (int arr[], int n)
{
int i, j, temp;
for (i = 0; i < n; ++i)
{
for (j = 0; j < n-i-1; ++j)
{
// Comparing consecutive data and switching values if value at j > j+1.
if (arr[j] > arr[j+1])
{
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}

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?

Table 8.3: Insertion Sort


Unsorted 78 23 45 8 32 36
Pass 1 23 78 45 8 32 36
Pass 2 23 45 78 8 32 36
Pass 3 8 23 45 78 32 36
Pass 4 8 23 32 45 78 36
Pass 5 8 23 32 45 36 78
Sorted 8 23 32 45 36 78

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);
}

void insertion(int fn_arr[])


{
int i, j, a, t;
for (i = 1; i < size; i++)
{
t = fn_arr[i];
j = i - 1;
while (j >= 0 && fn_arr[j] > t)

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?

A pointer is a variable whose value is the address of another variable. A pointer is a


variable of special kind which can contain a memory address of the primary memory.
This memory location in turn contains a value of some kind.

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:

int num = 25;

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 << &num;
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.

9.1.2. Reference and Dereference Operators


Consider the following:
Mphatso = 25; // Mphatso is assigned a value of 25
Mercy = Mphatso;//copies the value of Mphatso (which is 25) to Mercy
John = &Mphatso;/*copies to John not the value contained in Mphatso
but a reference to it (i.e., its address), John should be declared as
pointer */

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

Figure 9.1: Reference and Dereference Operators

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

1776 1776 1776


25 (Memory)

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.”

9.1.3. Declaring Pointers


A pointer variable is a variable that holds addresses of memory locations. Like other data
values, memory addresses, or pointer values, can be stored in variables of the
appropriate type. A variable that stores an address is called a pointer variable, but is
often simply referred to as just a pointer. The definition of a pointer variable, say ptr,
must specify the type of data that ptr will point to. A pointer is declared as:
datatype* variable_name
OR
datatype *variable_name // note the positions of * (asterisk)

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.

9.1.4. Assigning Values to Pointers


After declaring a pointer, you can assign a value (an address of a variable) to it. Address
of a variable is &variable_name. For the variables declared in the stack, we use &
operator to obtain their addresses which can be assigned to a pointer.
int num;
int *pNum; //pointer declaration
pNum = &num; //assign address of num to pointer pNum

210
You can also assign a value to a pointer during declaration.
int* pNum = &num;

During pointer declaration, you cannot assign a fixed value


int* pNum = 25;//This is wrong, pNum has no address currently
You can echo the value pointed by the pointer as:
cout << *pNum; //pNum being a pointer - this may print 25
If you write something like
cout << pNum; //pNum without a * (dereference operator)
The address referenced by pNum will be printed such as 0xbfebd5c0

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;

9.2.2. Pointer Arithmetic


Some mathematical operations may be performed on pointers. Pointer arithmetic involves
incrementing (add a value to) and decrementing (subtract a value from) a pointer. Hence
the valid operators are plus (+) and minus (-). But remember a pointer stores the address
of a variable, therefore its arithmetic is different from those of ordinary variables. Adding
two pointers together won’t be sensible. Incrementing and decrementing a pointer
behaves differently according to the size of the data type to which they point.

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

Figure 9.3: Pointer Arithmetic- integer variable

1998 1999 2000 2001 2002


Addresses
1.75

Values pDNum
dNum

Figure 9.4: Pointer Arithmetic- double variable


Now let’s see the result of:
pINum = pINum + 1; //equivalent to pINum++;

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

Figure 9.5: Pointer of Pointer illustration

From the illustration:


• num with address of 1000 and a value of 20
• pNum, a pointer to num, hence has a value of 1000 (address of num). Its address
in memory is 4000
• ppNum a pointer of a pointer. It is pointing to pNum, hence it has a value of 4000
(address of pNum). Its address in memory is 6000.

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 = &num; //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.

9.3. Functions and Pointers


Pointers are mainly used as parameters of a function. Using pointers as parameters of a
function saves memory and time. This is so because it’s only the address which is sent
and not the actual data. Imagine sending an object to a function which is several
megabytes big. This will require more memory and execution time. But all that memory
and time is saved if we just send an address, which is just some bytes big.

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)

Example: a program to check @ in email address


#include <iostream>
using namespace std;
void find(char* str);
int main()
{
char cString[9];
char* pString = cString;
cout << "Enter an Email Address: ";
[Link](cString,8);
find(pString);
[Link]();
return 0;
}
void find(char* str)
{
for(int p=0; p<8; p++)
{
if(*str == '@')
cout << "It is an email address";
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
}

Example: Program to generate and return random numbers


#include <iostream>
#include <ctime>
#include <cstdlib>
using namespace std;
int * getRandom(); //function prototype
int main ()
{
int *p; // a pointer to an int
p = getRandom(); //function call
for (int i = 0; i < 10; i++)
{
cout << "*(p + " << i << "): ";
cout << *(p + i) << endl;
}
return 0;
}
//function to generate and return random numbers
int * getRandom()
{
static int r[10];
srand((unsigned)time (NULL)); // set the seed
for (int i = 0; i < 10; ++i)
{
r[i] = rand();
cout << r[i] << endl;
}
return r;
}

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.

Example: Assume a program has a pointer to an int defined as:


int *ptr;
This is how you create a memory on a heap in C++
int *ptr = new int;//returned address is stored in pointer ptr

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.

A value may be stored in this new variable by dereferencing the pointer:


*ptr = 25;
Any other operation may be performed on the new variable by simply using the
dereferenced pointer:
cout << *ptr; //Display the contents of the new variable.
cin >> *ptr; // Let the user input a value.
total += *ptr; // Use the new variable in a computation.

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];

Memory allocated is de-allocated (freed) by using delete key word as below:


delete ptr; //deletes memory referenced by pointer ptr

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

To delete an array’s dynamic memory use delete[] as shown below:


delete[] gradesArr; //deletes an array memory

9.4.2. Memory Leak


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. The leaked block of memory
remains unavailable for use until the program terminates. Memory leaks are especially
serious when they occur in loops.

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 */
}

9.4.3. Dangling Pointer


A pointer is said to be dangling if it is pointing to a memory location that has been freed
by a call to delete. When you access a dangling pointer, you are trying to use memory
that has already been freed and returned to the heap.

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

9.4.4. Void Pointer


• A void pointer is a generic pointer.
• It can store the address of any data type.
• Syntax
void *ptr;

Problem Without Void Pointer


• In C++, you cannot assign different data types to a pointer:
int *ptr;
float a = 10.2;
ptr = &a; // ERROR (int pointer cannot store float address)

Solution: Use Void Pointer


#include <iostream>
using namespace std;

int main() {
void *ptr; // void pointer
int a = 9;

ptr = &a; // allowed

cout << &a << endl; // address of a


cout << ptr << endl; // same address stored in void pointer

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;

cout << *(int*)ptr; // typecasting required

9.4.5. Null Pointer


• A null pointer is a pointer that does not point to any memory location.
• Syntax
int *ptr = nullptr;

Why Use Null Pointers?


• To avoid garbage values
• To check if pointer is valid before use

Example
int *ptr = nullptr;

if (ptr != nullptr) {
cout << *ptr;
}
else {
cout << "Pointer is NULL";
}

9.4.6. Array of Pointers


• An array of pointers is an array where each element is a pointer.
• Syntax:
dataType *arrayName[size];
• Example:
#include <iostream>
using namespace std;

int main() {
const char* names[] = {"Alice", "Bob", "Charlie"};

cout << names[1]; // Bob


return 0;
}
• Each element stores the address of a string.

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;

// *ptr = 20; Not allowed


ptr = &var2; // Allowed

2. Constant Pointer
• You cannot change the pointer, but you can change the value.
int var = 10;
int *const ptr = &var;

// ptr = &var2; Not allowed


*ptr = 20; // Allowed

3 Constant Pointer to Constant


• You cannot change pointer and cannot change value.
int var = 10;
const int *const ptr = &var;

// ptr = &var2; Not allowed


// *ptr = 20; Not allowed

Common Pointer Pitfalls


1. Dangling Pointer
• Pointer points to invalid memory (memory freed or out of scope).
int *ptr;
{
int x = 10;
ptr = &x;
} // x destroyed → ptr becomes dangling

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

4. Null Pointer Check (Best Practice)


if (ptr != nullptr) {
cout << *ptr;
}

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.

struct: is a collection of a fixed number of components in which the components are


accessed by name. The components may be of different types. The components of a
struct are called the members of the struct.

10.1.1. Defining a structure


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. Structure definition can be
placed before main function if you want it to be accessible by all functions or it can be
within main function if you want it to be local to the main().

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.

struct: Is a key word for defining a structure

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;

There must be a semicolon after the closing brace of the declaration.

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.

10.1.2. Declaring and Initiating Structure Variables


After the structure is defined, then you can use it in a variable declaration, the same way
you declare variables of type int, char, double. The variables declared using structure
are called objects. The declaration of these objects is known as instantiation.

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

A structure can have a function called constructor. A structure constructor is essentially


a special member function that is automatically called when an object of the structure is
created.
struct Student
{
/* members here (skipped) */
Student (int a, char *b, char c, double d)
{
id = a;
name = b;
gender = c;
average = d;
}
};

You can also initialize values to structure members at declaration.


Example: Books structure can be initialized at object instantiation as follows:
Books Book1 = {“Programming”,”Joel Manda”, “Arrays”, 0001};

Example: Student structure can be initialized at object instantiation as follows:


Student s1 = {1,”John Banda”, ‘M’,63.5};

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.

Example: Using Books structure declaration.


Book1.book_id= 0002; // will change books book id to 0002.

Example: Using Student structure declaration.


Student s1;
[Link] = 02;
[Link] = “Mercy Banda”;
[Link] = ‘F’;
[Link] = 63.5;

10.1.4. Accessing Structure Data


To access data from object’s members you use object name and member name
separated by a dot (.) 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;
}

10.2. Nested Structures


A structure can be nested in another structure, the process called object composition.
Instances of one structure can be nested within another structure. For example, consider
the following structure declarations:

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.

Assume variable Phone is defined to be an Item structure:


Item Phone;

Then values assigned to it as:


[Link] = "123A";
[Link] = “Sumsung S24 Ultra 12GB 256GB";
[Link] = 1400000.0;
[Link] = 1450000.0;

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];

You can initialize array this way:


Student students[ ] = {
{1, “Zanga Zatha”, ‘M’, 63.5},
{2, “Chikonzero Chake”, ‘F’, 55.6},
{3, “ Alekeni Anene”, ‘M’, 68.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.

Student * s1 = new Student;


s1->id = 1;
s1->name = “Mercy Banda”;
s1->sex = ‘F’;
s1->average = 63.5;

Activity 10.3
What is self-referential structure?

10.4. Functions and Structures


Structures can be passed to a function by value, by reference and even by pointers.
Passing structures by value is not desirable as it wastes memory and increases program
runtime, unless the structure is quite small. It is therefore recommended that you should
always pass structures by reference (pointer). In cases where you don’t want the function
to modify the structure, then it is passed as constant reference.

Structures can be sent to functions as a reference parameter, array parameter and


pointer parameter. A function can return a structure, since structure holds more than one
data items (members), then structures gives an opportunity to return more than one value
from a function. The following examples, uses display() function which prints the
content of structure sent to the function.

10.4.1. Reference parameter


void func(Student &s);
int main()
{
Student s1;
func(s1); //calls a function (protype above)
return 0;
}

236
Example: Using Student Structure

Remember we use & in parameter for reference parameter.


#include<iostream>
using namespace std;
struct Student
{
int id;
string name;
char gender;
double average;
};
void display(Student &s);
int main()
{
Student students = {1, “Zanga Zatha”,’M’,63.5};
display(students);
return 0;
}
void display(Student &s)
{
cout << [Link] << “\t” << [Link] << “\t” << [Link] << “\t”
<<[Link] << endl;

10.4.2. Array parameters


void func(Student s[]);
int main()
{
Student s1[3];
func(s1); //calls a function (protype above)
return 0;
}

Example: Using Student Structure


#include<iostream>
using namespace std;
struct Student
{
int id;
string name;
char gender;
double average;
};

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;
}
}

10.4.3. Pointer parameter


void func(Student *s);
int main()
{
Student* s1 = new Student;
func(s1); //calls a function (protype above)
return 0;
}

Example: Using Student Structure


#include<iostream>
using namespace std;
struct Student
{
int id;
string name;
char gender;
double average;
};
void display(Student *s, const int n);
int main()

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

Unions are especially important in:


• Embedded systems
• Low-level programming
• Memory-efficient applications

Union vs Structure
Although unions and structures look similar, they differ significantly in how memory is
allocated.

Table 10.1: Union vs Structure


Feature Structure Union
Memory Each member has its own All members share same
allocation memory memory
Storage All values stored at once Only one value at a time
Memory usage Sum of all members Size of largest member
Efficiency Less memory efficient More memory efficient

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;
};

• The union Pay has two members:


o hours of type short
o sales of type float
• Both members share the same memory location
• Only one member can be used at a time

Creating a Union Variable


Pay employee1;

Here:
• employee1 is a variable of type Pay
• It can store either hours or sales, but not both at the same time

Memory Allocation in a Union


• The memory allocated to a union is equal to the size of its largest member.

Example Memory Analysis


union Pay
{
short hours; // 2 bytes
float sales; // 4 bytes
};
• Memory usage:
o Largest member = float (4 bytes)
o Total memory used by union = 4 bytes

How Data Is Stored in a Union


• When a value is stored in sales, all 4 bytes are used
• When a value is stored in hours, only the first 2 bytes are used
• Writing to one member overwrites the data stored in the other member

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.

Accessing Union Members


• Union members are accessed using the dot (.) operator, just like structures.
[Link] = 35;
[Link] = 2000.50;

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

Best Practices When Using Unions


• Use unions only when memory optimization is necessary
• Clearly document which member is active
• Combine unions with enumerations (enum) to track active data
• Prefer structures if all values are needed simultaneously

Practical Applications of Unions


• Payroll systems (hours or sales-based pay)
• Network protocol handling
• Device drivers
• Embedded systems
• Variant data storage

Activity 10.5
i. How are unions similar to structures?
ii. How are unions different from structures?

10.6 Enumerations (Enums)


An Enumeration (enum) in C++ is a user-defined data type that consists of a set of
named constant values.

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;

enum Color { RED, GREEN, BLUE };

int main() {
Color c = RED;

cout << "Color value: " << c << endl;


return 0;
}

• By default:
o RED = 0
o GREEN = 1
o BLUE = 2

Enum Values and Integer Representation


• Enum constants are stored internally as integers
• Default starting value is 0
• Each next value increases by 1

Example
enum Days { MON, TUE, WED, THU, FRI };

Enum Constant Integer Value


MON 0
TUE 1
WED 2
THU 3
FRI 4

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;

enum Status { SUCCESS = 1, FAILURE = 0 };

int main() {
Status s = SUCCESS;
cout << s << endl; // Output: 1
return 0;
}

Using Enums in Conditional Statements


• Enums are commonly used with if and switch.
Example using switch
#include <iostream>
using namespace std;

enum Menu { ADD = 1, SUB, MUL, DIV };

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;

enum Operation { ADD, SUB };

void calculate(Operation op) {


if(op == ADD)
cout << "Addition operation";
else
cout << "Subtraction operation";
}

int main() {
calculate(ADD);
return 0;
}

Enum Scope Rules

1. Traditional Enums
• Enum values are placed in the same scope
• Can cause name conflicts
enum Status { ON, OFF };
enum Switch { ON, OFF }; // Error

2. Scoped Enumerations (enum class) – Modern C++


• Introduced in C++11 to avoid naming conflicts.

Syntax
enum class Color { RED, GREEN, BLUE };

Example
#include <iostream>
using namespace std;

enum class Color { RED, GREEN, BLUE };

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);

Practical Uses of Enums


Enums are commonly used in:
• Menu-driven programs
• Days of the week
• Grades and status codes
• Game states
• Error handling
• Finite state machines

Advantages of Enums
• Improves program clarity

• Prevents invalid values


• Makes debugging easier
• Enhances maintainability
• Groups related constants together

Limitations of Enums
• Limited to predefined values

• Traditional enums allow implicit integer conversion


• No built-in string representation

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

Example: Program to change lowercase letter to uppercase


#include<iostream>
using namespace std;
int main()
{
char letter;
cout << “Enter a letter in lower case =>”;
cin >> letter;
cout << “Your letter in upper case is =>”
<< (char) (letter-32);
return 0;
}

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.

11.2.1. Null-terminated strings


Null-terminated strings are stored with \0 (null character) at the end. Example of
declaration of null-terminated string is:
char firstname[10];

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

Figure 11.1: Graphical representation of Null-terminated strings

You can initialize string at declaration as follows:


char firstname[5] = {‘J’, ’o’, ’h’, ’n’, ’\0’}; or
char firstname[] = “John”;

To get string from the user (keyboard) use:


cin >> firstname;

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.

11.2.2. Library Functions for Working with C-Strings


The C++ library provides many functions for working with C-strings. There are functions
for determining the length of a string, for concatenating two strings, for comparing two
strings, and for searching for the occurrence of one string within another. You must
include the cstring header file to use these functions.

[Link]. The strlen Function – Length of a String


The strlen function is passed a C-string as its argument, and returns the length of the
string. This is the number of characters up to, but not including, the null terminator.

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)

so, cast it as:


cout << (char) toupper(‘a’); //this returns A

[Link]. The strcpy Function – Copying a string


C++ has inbuilt function strcpy in string header which is used to copy string to another
string. It accepts two C-strings as arguments. The function copies the second C-string to
the first C-string. The second C-string is left unchanged. The destination string should be
declared with a size greater than or equal to that of the source string.

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;

[Link] The strncpy Function – Copying a substring


String header has also built-in function, strncpy(), which extracts some characters
from one string to the other. It copies at most n characters of string2 to string1. If
string2 has fewer than n characters, then string1 is padded with ‘\0’ characters until
a total of n characters have been written to it. If string2 has n or more characters, then
the first n characters are copied and string1 is not null-terminated.

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”

To only copy “bet” use the following:


strncpy(name2, name1+5, 3);//5 shows a position to start copying

[Link] The strcat Function – Concatenating Strings


Concatenating strings is adding strings together. String header has built-in function,
strcat(), which is used to concatenate strings. It Accepts two C-strings as arguments.
The function appends the contents of the second string to the first C-string. (The first
string is altered; the second string is left unchanged.)

General Syntax:

strcat(string1, string2);

Example:
char name1[20] = “Elizabeth”;
char name2[] = “Banda”;
strcat(name1, name2);
Cout << name1; //This prints “Elizabeth Banda”

[Link] The strcmp Function – Comparing Strings


String header has built-in function, strcmp(), which is used to compare two strings.
Strings are compared lexicographically. It accepts two C-string arguments. If string1
and string2 are the same, this function returns 0. If string2 is alphabetically greater

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);

Example: Program to print names in alphabetical order.

#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;
}

[Link] The strstr Function – searching a string


Returns a pointer to the first occurrence of string string2 in string string1. Searches
for the first occurrence of string2 in string1. If an occurrence of string2 is found,
the function returns a pointer to it. Otherwise, it returns a NULL pointer (address 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.”

char strArray[] = “ A string is array of characters “;


char *name;
cout << strArray << endl;
name = strstr(strArray, “array”); // search for “array”
cout << name << endl;

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

strchr(string1, ch); returns a pointer to the first occurrence of character ch in


string string1.

11.2.3. String Data Type


C++ provides another way of handling string- using string Class. This way does not
require <string.h> header.

Declaring a string
General syntax:
string string_name;
Example:
string firstname;
It can be initialized as:
string firstname = “John”;

To get length of string do:


[Link]();

257
To concatenate strings, do:
firstname + surname;
e.g. cout<< firstname + surname;

To copy a string do:


firstname2 = firstname; /* this copies value of firstname
to firstname2 */

Activity 11.2b
What will the following program segment display?
char dog[] = "Poppy";
cout << strlen(dog) << endl;

11.3. Array of Strings


If you want to keep three names in an array. That calls for array of strings. Array of strings
is 2-Dimensional Array of Characters. Declaration of array of strings is:
char names[3][20]; //space to keep 3 names

To print a name from array of strings use;


cout << names[0]; // first name
cout << names[1]; //second name
cout << names[2]; //third name

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:

Table 11.1: Two-Dimensional String Array


0 1 2 3 4 5 6 7
0 J o h n \0
1 E d w a r d \0
2 B o b \0
3 E v e \0
4 A d a m \0

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”.

Conversion Between String and Other Data Types in C++


• In C++, it is often necessary to convert strings into numeric values (such as int,
float, double) and convert numbers back into strings.

Why Conversion Is Needed


• User input is often taken as strings
• Mathematical operations require numeric data
• Output formatting sometimes needs strings
• File handling and data processing rely heavily on conversions

Methods of Conversion in C++


C++ provides three main approaches for converting between strings and other data
types:
1. C-style functions
(e.g., atoi, atof, atol, sprintf)
2. C++ String Streams
(stringstream)
3. Modern C++ functions (C++11 / C++17)
(stoi, stof, stod, to_string)

259
Converting from String to Numeric Types (C-Style Functions)
• These functions are defined in the <cstdlib> header.

1. atoi() – String to Integer


• Converts a C-string to int
• Stops conversion when a non-digit is found
#include <cstdlib>
int num = atoi("123"); // num = 123
• If conversion fails, result may be 0

2. atof() – String to Float


#include <cstdlib>
float f = atof("3.14"); // f = 3.14

3. atol() – String to Long


#include <cstdlib>
long l = atol("999999"); // l = 999999

Converting from Numeric Types to String (C-Style)


Using sprintf()
• Converts numbers to strings
• Defined in <cstdio>
#include <cstdio>

char str[10];
int x = 123;

sprintf(str, "%d", x); // str becomes "123"

• Common format specifiers:


o %d → int
o %f → float
o %lf → double

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

1. Number to String using stringstream


#include <sstream>
#include <string>

int num = 45;


stringstream ss;

ss << num;
string str = [Link](); // "45"

2. String to Number using stringstream


#include <sstream>
#include <string>

string input = "67";


stringstream ss(input);

int value;
ss >> value; // value = 67

• << inserts data into stream


• >> extracts data from stream
• Useful when converting multiple values

Modern C++ Conversion Functions (Recommended)


• These functions are defined in <string> and available in C++11 and later.

1. Number to String – to_string()


#include <string>

int num = 100;


string str = to_string(num); // "100"

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

stof() – String to Float


float y = stof("3.14"); // 3.14

stod() – String to Double


double z = stod("6.28"); // 6.28

Advantages of Modern Functions


• Work directly with std::string
• Better error handling
• Cleaner and easier syntax

Complete Example Program


• Input strings → convert to integers → add → convert result back to string
#include <iostream>
#include <string>
using namespace std;

int main() {
string str1 = "25";
string str2 = "30";

int num1 = stoi(str1);


int num2 = stoi(str2);

int sum = num1 + num2;

string result = to_string(sum);

cout << "Sum as string: " << result << endl;


return 0;
}

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.

12.1. Programming Paradigms


In the realm of high-level programming languages, there are various approaches or styles
to structure and organize code. These approaches are often referred to as programming
paradigms. Historically, programming languages have evolved from simpler, linear
execution models to more complex, modular, and reusable structures. Broadly, high-level
programming languages can be categorized into two major paradigms:
i. Procedure-Oriented Programming (POP) Language
ii. Object-Oriented Programming (OOP) Language

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.

Object-Oriented Programming (OOP) offers several substantial benefits and advantages


to both the software designer and the end-user. It plays an essential role in various
modern applications, including user interface design, complex simulations, advanced
modeling, and many more.

12.1.1. Procedure-Oriented Programming (POP) Language


Procedure-Oriented Programming (POP) is a traditional programming paradigm that
focuses on sequences of actions or steps to solve a problem. In POP, the problem is
typically viewed as a series of things to be done, such as reading input, performing
calculations, and printing results.

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.

• Large Programs Divided into Functions: To manage complexity, large programs


in POP are divided into smaller, self-contained units known as functions (also
called procedures or subroutines). Each function performs a specific task.

• Global Data Access: A significant characteristic of POP is that most functions


often share global data. This means that data is typically stored in global variables
that can be accessed and modified by any function in the program.

• 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.

• Employs Top-Down Approach: Program design in POP typically follows a top-


down approach. This means the problem is broken down into smaller sub-
problems, and each sub-problem is then further divided until it becomes
manageable functions.

[Link]. Disadvantages of Procedure-Oriented Programming


Despite its simplicity for smaller programs, POP presents several disadvantages,
especially for larger and more complex applications:
• Global Data Access: The widespread use of global data is a major drawback.
When many functions can access and modify the same global data, it becomes very
difficult to track changes, debug errors, and ensure data integrity. A change in one
function might unintentionally affect another function that relies on the same global
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.

12.1.2. Object-Oriented Programming (OOP)


Object-Oriented Programming (OOP) represents a paradigm shift from procedure-
oriented programming. It is an approach or a programming pattern where programs are
structured around objects rather than functions and logic. The central idea is to
combine data and the functions that operate on that data into a single unit, known as an
object.

[Link]. Core Philosophy of OOP


• Data Partitioned into Memory Areas: OOP makes the data partitioned into two
distinct memory areas: one for data (attributes) and another for functions
(methods). This partitioning helps in making the code more flexible and modular.

• Focus on Objects: Object-oriented programming primarily focuses on objects that


are required to be manipulated. Instead of a sequence of actions, the program
becomes a collection of interacting objects.

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().

• Modularizing Programs: OOP provides a powerful way of modularizing programs


by creating partitioned memory areas for both data and functions that are tightly
bound together. These combined units (objects) can then be used as templates for
creating copies of such modules on demand. This means you can define a
blueprint (class) once and create many instances (objects) from it.

[Link]. Features of Object-Oriented Programming


OOP introduces several key features that address the limitations of POP and provide a
more robust and scalable approach to software development:
• Emphasis on Data (Objects) rather than Procedure: Unlike POP, which
emphasizes the sequence of operations, OOP places a strong emphasis on the
data and how it is structured within objects.

• 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.

• Data Structures Characterize Objects: Data structures (data members) are


designed specifically to characterize the objects. They hold the state or properties
of an object.

• 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.

• Objects Communicate through Functions: Objects interact with each other by


sending messages, which are essentially calls to each other's public member
functions. This controlled communication ensures proper interaction and data flow.

• 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.

• Follows Bottom-Up Approach: Program design in OOP typically follows a


bottom-up approach. This means you start by designing the individual objects and
classes, and then integrate them to build the larger system. This mirrors how
complex systems are often built from smaller, self-contained components.

12.1.3. Basic Concepts of Object-Oriented Programming (OOPs)


The main aim of OOP is to bind together the data and the functions that operate on
them so that no other part of the code can access this data except that function.
This principle is fundamental to the integrity and security of object-oriented systems. To
achieve this, OOP relies on several basic concepts that act as its building blocks:

[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.

[Link]. Data Abstraction


Data abstraction refers to the act of representing essential features without
including the background details or explanations. It is about showing only what is
necessary and hiding the complex implementation details.
• Simplifying Complex Systems: Abstraction involves simplifying complex systems
by modeling classes based on their essential properties and behaviors.
• Focus on 'What' vs. 'How': It focuses on what an object does (its interface)
rather than how it achieves it (its internal implementation). For example, when
you use a remote control to turn on a TV, you only care about the "on" button, not
the intricate electronic circuits inside the TV.

[Link]. Data Encapsulation


Data encapsulation is the wrapping up of data and functions into a single unit
(called a class). It is the mechanism that binds together data and the methods that
operate on that data, preventing direct access to the data from outside the bundle.

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.

• Establishes Class Hierarchy: It creates a hierarchy of classes, reflecting real-


world relationships (e.g., a Car is a Vehicle, a Dog is an Animal).

[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.

• Treating Objects of Different Classes Uniformly: Polymorphism allows objects


of different classes to be treated as objects of a common base class. This enables
flexibility and extensibility in the code, as you can write generic code that works
with a variety of related objects.

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.

• Linked to Polymorphic Reference: It is intrinsically linked to polymorphic


references. The specific function that gets executed depends on the dynamic type
(actual type) of the object being referred to at runtime, rather than the static type
(declared type) of the pointer or reference. This is what enables the power of virtual
functions in C++.

[Link]. Message Passing


An object-oriented program consists of a set of objects that communicate with each
other. This communication happens through a mechanism called message passing.
• Request to Execute a Procedure: A message to an object is essentially a request
to execute a procedure (a member function), which then triggers a function within
the receiving object to produce the desired result.

• Components of a Message: Message passing involves providing:


o The name of the object to which the message is being sent.
o The name of the function (message) that is requested to be executed.
o Any necessary information (arguments) to be transmitted along with the
message.

12.1.4. Benefits of Object-Oriented Programming (OOP)


The adoption of Object-Oriented Programming brings numerous advantages to the
software development process:
1. Modularity
• OOP promotes modularity by breaking down a complex system into smaller,
manageable, and self-contained units (objects).

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.

3. Flexibility and Extensibility


• OOP provides a highly flexible and extensible framework for software

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.

5. Understanding and Modeling the Real World


• One of the most intuitive benefits of OOP is its ability to allow developers to model
real-world entities and their relationships in a natural and intuitive way.
• By representing real-world objects (like students, cars, bank accounts) directly in
code, the alignment between the program's structure and the real-world scenarios

273
it simulates is enhanced. This direct mapping makes the code more
understandable, relatable, and easier to reason about for developers.

12.1.5. Applications of OOP


The versatility and benefits of Object-Oriented Programming have led to its widespread
adoption across various domains. The most popular application of OOP has historically
been in user interface design, particularly in the development of windowing systems.
Numerous graphical user interface (GUI) frameworks and libraries have been built using
OOP techniques, as the concepts of objects (windows, buttons, menus) and their
interactions map perfectly to the OOP paradigm.
Beyond user interfaces, OOP is invaluable in complex real business systems that often
contain many objects with intricate attributes and methods. OOP helps simplify these
complex problems by breaking them down into manageable, interacting objects.

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.

2. Simulation and Modeling: OOP is excellent for creating simulations of real-world


phenomena (e.g., weather patterns, traffic flow, biological systems) because
objects in the simulation can directly correspond to real-world entities.

3. Object-Oriented Databases: Databases designed to store and manage objects


directly, rather than just relational data, leverage OOP principles for more natural
data representation and manipulation.

4. Hypertext, Hypermedia, and Expertext: Systems involving interconnected


information (like the web) can be effectively modeled using objects, where each
piece of content or link can be an object.

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.

6. Neural Networks and Parallel Programming: The modular nature of objects


makes OOP suitable for designing and implementing neural networks and parallel
programming paradigms, where independent units can process data concurrently.

7. Decision Support and Office Automation Systems: Complex business


applications that assist in decision-making or automate office tasks can be
structured effectively using OOP, managing various data entities and business
logic as objects.

8. CIM (Computer Integrated Manufacturing), CAM (Computer-Aided


Manufacturing), and CAD (Computer-Aided Design) Systems: These
engineering and manufacturing systems heavily rely on modeling physical
components and processes, making OOP an ideal choice for their development
due to its ability to represent real-world entities as objects.

Activity 12.1
How does encapsulation contribute to the modularity of code in OOP?

12.2. Classes and Objects


In Object-Oriented Programming (OOP), classes and objects are fundamental concepts
that form the backbone of how programs are structured and how real-world entities are
modeled. They are the primary tools for implementing encapsulation, abstraction,
inheritance, and polymorphism.
• Class: A class serves as a blueprint or a template for creating objects. It defines
a new data type by bundling together data (attributes) and the methods
(functions) that work on that data into one single, cohesive unit. Think of a class
like a cookie cutter; it defines the shape and characteristics of the cookies, but it's
not a cookie itself.

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.

12.2.1. Understanding the Concept of a Class


A class is more than just a blueprint; it's a powerful construct that allows us to define
custom data types that closely resemble real-world entities.
• Group of Objects with Common Properties and Relationships: A class acts as
a logical grouping for objects that share similar characteristics (data members) and
behaviors (member functions). For instance, all Student objects will have a name,
age, and grade, and they will all be able to displayInfo().

• 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++.

12.2.2. Class Specification: Declaration and Definition


Generally, a class specification in C++ has two main parts:
i. Class Declaration: The class declaration describes the type and scope of its
members. This is where you declare the data members (variables) and member
functions (methods) that belong to the class, along with their access specifiers. It
defines the interface of the class.

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.

12.2.3. Defining a Class: Syntax


A class is defined using the class keyword, followed by the class name, and a pair of curly
braces {} that enclose its members.

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;
};

[Link]. Class Example


Let's look at a simple Student class example:
class Student {
public: // Access specifier: Members declared here are
accessible from outside the class
string name; // Data member (attribute) to store student's name
int age; // Data member (attribute) to store student's age
float grade; // Data member (attribute) to store student's grade

// Member function (method) to display student information


void displayInfo() {
cout << "Name: " << name << endl;
cout << "Age: " << age << endl;
cout << "Grade: " << grade << endl;
}
};

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;

public: // Public members: accessible from outside the class


// Setter function to set private data
void setDetails(string n, int a, float g) {
name = n;
age = a;
grade = g;
}

// Getter/Display function to show private data


void displayInfo() {
cout << "Name: " << name << endl;
cout << "Age: " << age << endl;
cout << "Grade: " << grade << endl;
}
};

In this example:
• name, age, and grade are private. This means you cannot directly write
[Link] = “Alice”; from main().

• setDetails() and displayInfo() are public. These functions act as the


controlled interface to interact with the private data members. You would call
[Link](“Alice”, 19, 85.0); to set the student’s
information.

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.

Syntax for Creating an Object:


ClassName objectName;

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.

12.2.6. Accessing Class Members


To interact with the data and functions within an object, you use the dot operator (.).
• The private data of a class can only be accessed through its member functions
(if those functions are public or protected and called from an appropriate scope).
This is the essence of encapsulation.

• public members (both data and functions) can be accessed directly using the dot
operator.

Syntax for Accessing a Member Function:


[Link](actual arguments);

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

// Calling the public member function setDetails() to set private data


[Link]("John Zathu", 20, 88.5);

// Calling the public member function displayInfo() to display private data


[Link](); // This would display the values of data
//members for student1

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).

12.2.7. Constructors and Destructors


Constructors and destructors are special member functions in C++ classes that are
automatically invoked at specific points in an object's lifecycle. They are crucial for
proper object initialization and resource management.

[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;
}

In this example, when Student student1("John Zathu", 21, 92.3); is


executed, the Student constructor is automatically called, initializing student1's name,
age, and grade with the provided values.

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.

ii. Parameterized Constructor:


o A constructor that takes one or more parameters.
o It allows you to initialize an object with specific values at the time of its
creation.

iii. Copy Constructor:


o A constructor that creates a new object as a copy of an existing object.
o It takes a reference to an object of the same class as its argument, typically
const ClassName&.
o The copy constructor is invoked in several situations:
▪ When an object is initialized with another object of the same class.
▪ When an object is passed by value to a function.
▪ When an object is returned by value from a function.
o If you don't provide a copy constructor, the C++ compiler provides a default
one that performs a member-wise (shallow) copy.

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.

12.2.8. Member Functions in Classes


Member functions are the functions defined inside the class and are designed to
access and operate on the data members of that class. They define the behaviors or
actions that objects of the class can perform.
• Purpose: They are used to perform operations on the data members of the class,
ensuring that data is manipulated in a controlled and consistent manner, adhering
to encapsulation principles.

• Definition Location: Member functions can be defined in two places:


o Inside the class definition.
o Outside the class definition.

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.

Example (Inside the class):


class Student {
public:
string name;
int age;

void displayInfo() { // Defined inside the class


cout << "Details of the student." << endl;
cout << "Name: " << name << endl;
cout << "Age: " << age << endl;
}
};

[Link]. Defining Member Functions Outside the Class


Member functions can also be defined outside the class definition. When defined outside,
you must use the scope resolution operator (::) to specify which class the function
belongs to. This is common practice for larger functions to keep the class declaration
clean and readable.

Syntax (Outside the class):


ReturnType ClassName::FunctionName(parameters) {
// function body
}

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();
};

// Function definitions outside the class, using the scope


// resolution operator (::)
void Student::setDetails(string n, int a, float g) {
name = n;
age = a;
grade = g;
}

void Student::displayInfo() {
cout << "Name: " << name << endl;
cout << "Age: " << age << endl;
cout << "Grade: " << grade << endl;
}

// Using Functions Defined Outside the Class


int main() {
Student student1;
[Link]("John Waka", 24, 87.9);
[Link]();
return 0;
}

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.

Objects as Function Arguments - Example (Pass by Value)


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 takes a Student object by value


void displayStudent(Student s){//'s' is a copy of the object passed
cout << "Displaying student details from within
displayStudent function:" << endl;
[Link]();
//Any changes to 's' here would not affect the original object in main
}

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.

12.2.10. Returning Objects from Functions


Functions can also return objects as their return type. This is useful when a function
needs to create and return a new object, or return an existing object.

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().

12.2.11. The this Pointer


The this pointer is a special, implicit pointer that is automatically available inside
every non-static member function of a class.
• Implicit Parameter: It acts as an implicit parameter to all non-static member
functions.
• Points to the Calling Object: The this pointer always points to the object for
which the member function is called. It's a self-referential pointer.
• Usage: It is primarily used to:
o Access data members and member functions of the current object.
o Differentiate between class members and local variables (or function
parameters) that have the same name.
o Return the current object from a member function (e.g., for method
chaining).

[Link]. The this Pointer - Example


The this pointer is particularly useful when a function parameter has the same name
as a class data member. Without this, there would be ambiguity.
class Student {
private:
string name;
int age;
float grade;
public:
// Parameters have the same names as data members
void setDetails(string name, int age, float grade) {
// Using 'this->' to refer to the class's data members
this->name = name;//Assigns parameter 'name' to class's 'name'
this->age = age; // Assigns parameter 'age' to class's 'age'
this->grade=grade;//Assigns parameter 'grade' to class's 'grade'
}

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.

12.2.12. Static Members


Static members are special members of a class that are shared by all objects of that
class, rather than each object having its own copy. They belong to the class itself, not
to any specific instance.

[Link]. Static Data Members


• Shared by All Objects: These are class variables that are shared by all objects of
the class. There is only one copy of a static data member for the entire class,
regardless of how many objects are created.
• Declaration: They are declared with the static keyword inside the class definition.
• Definition and Initialization: Static data members must be defined and
initialized outside the class definition in the global scope. This is where
memory is allocated for them.

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.

Static Members - Example


class Student {
private:
string name;
int age;
float grade;
static int studentCount; // Static data member: shared by
//all Student objects
public:
Student(string n, int a, float g) {
name = n;
age = a;
grade = g;
studentCount++; // Increment count whenever a new
//Student object is created
}
static int getStudentCount() { // Static member function
return studentCount;//Can only access static data members
}
void displayInfo() {
cout << "Name: " << name << endl;
cout << "Age: " << age << endl;
cout << "Grade: " << grade << endl;
}
};
// Define and initialize the static data member outside the class
// This is where memory for studentCount is allocated and initialized
to 0

294
int Student::studentCount = 0;

int main() {
// Access static member function using class name
cout << "Initial total students: " <<
Student::getStudentCount() << endl; // Output: 0

Student student1("Alice Phiri",19,85.0);//studentCount becomes 1


Student student2("Bob Wiki", 20, 90.5);// studentCount becomes 2

// Access static member function using class name


cout<<"Total students: "<<Student::getStudentCount()<< endl;
// Output: 2
[Link]();
[Link]();

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.

12.2.13. Const Member Functions


const member functions are member functions that are guaranteed not to modify the
object on which they are called. They provide a level of safety and clarity, indicating that
the function is an "accessor" (reads data) rather than a "mutator" (modifies data).
• Declaration: They are declared by placing the const keyword after the parameter
list and before the function body.

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.

[Link]. Setter and Getter Functions


• Setter Function (Mutator Function): A setter function is a method in a class that
allows you to modify or set the value of a private member variable from
outside the class. They "mutate" (change) the object's state.

• Getter Function (Accessor Function): A getter function is a method that allows


you to retrieve or "get" the value of a private member variable from outside
the class. Getter functions are typically declared as const member functions
because they should not modify the object's state.

Const Member Functions - Example


class Student {
private:
string name;
int age;
float grade;
public:
Student(string n, int a, float g) :
name(n), age(a), grade(g) {}

// Setter function to set details (modifies the object, so NOT const)


void setDetails(const string& n, int a, float g) {
name = n;
age = a;
grade = g;
}

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

// Example with a const object:


const Student student2("Alice Smith", 20, 95.0);
[Link]();//OK: displayInfo()is a const member
function
// [Link]("Bob", 21, 80.0); // ERROR: Cannot call
//non-const method on const object

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.

In C++, inheritance is a powerful mechanism that enables developers to create new


classes based on existing ones, significantly promoting code reuse and reducing
redundancy. Instead of writing the same code multiple times for similar functionalities,
you can define common attributes and operations in a base class and then have other
classes inherit them. This leads to more organized, efficient, and maintainable code.

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.

12.3.1. Types of Inheritance


C++ supports various types of inheritance, allowing for flexible class hierarchies.

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;
}
};

class StudentGrades : public Student, public Attendance {


private:
char grade;
public:
void setGrade(char g) {
grade = g;
}
void displayStudentDetails() {
// Assuming Student class has displayStudentInfo()
displayStudentInfo(); // Inherited from Student
displayAttendance(); // Inherited from Attendance
cout << "Grade: " << grade << 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())
};

class Grades : public Student {


// Derived from Student (e.g., grade, displayGrade())
};

class TestScores : public Grades {


private:
int score;
public:
void setScore(int s) {
score = s;
}
void displayTestDetails() {
// Assuming Grades class has displayGrade() and Student has
//displayStudentInfo()
displayStudentInfo(); // Inherited from Student via Grades
displayGrade(); // Inherited from Grades
cout << "Test Score: " << score << endl;
}
};

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)
};

class Sports : public Student {


private:
string sport;
public:
void setSport(string s) {
sport = s;
}
void displaySport() {
cout << "Sport: " << sport << endl;
}
};

class Arts : public Student {


private:
string artForm;
public:
void setArtForm(string a) {
artForm = a;
}
void displayArt() {
cout << "Art Form: " << artForm << endl;
}
};

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;
};

class Student : public Person { // Single Inheritance (Student from


// Person)
protected:
int id;
};

class Test : public Student { // Multilevel Inheritance (Test from


// Student, Student from Person)
private:
int testScore;
public:
void setInfo(string n, int a, int r, int s) {
name = n; // Inherited from Person
age = a; // Inherited from Person
id = r; // Inherited from Student
testScore = s; // Own member
}
void display() {
cout << "Name: " << name << ", Age: " << age
<< ", Student ID: " << id << ", Test Score: "
<< testScore << endl;
}
};

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.

Constructors and Inheritance


When dealing with inheritance, the order and mechanism of constructor calls are
important.
• When a derived class object is created, the constructor of the base class is
automatically called before the constructor of the derived class. This ensures
that the base part of the object is properly initialized before the derived part.
• If the base class has a constructor with parameters, the derived class needs to
explicitly pass the appropriate arguments to the base class constructor. This is
typically done using an initialization list in the derived class's constructor.

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;
}
};

class Grades : public Student {


private:
char grade;
public:
// Constructor for Grades, explicitly calling Student constructor
Grades(string n, int id, char g) : Student(n, id), grade(g) {
cout << "Grades Constructor Called" << 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;
}

In this example, when a Grades object is created, its constructor Grades(string n,


int id, char g) first calls the Student constructor Student(n, id) using the
initialization list Student(n, id). This ensures that the name and studentID
members are initialized by the Student constructor before the grade member is
initialized by the Grades constructor.

12.3.2. Complex Objects (Composition)


• A complex object is an object that is made up of other objects.
• This is achieved using composition (HAS-A relationship).
• Composition is preferred when:

o Objects are strongly dependent


o One object cannot exist meaningfully without the other

Table 12.1: Composition vs Inheritance


Inheritance Composition
IS-A relationship HAS-A relationship
Student IS-A Person Student HAS-A Grade
Uses : Uses object members

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';
}
};

Student Class Using Composition

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;
}
};

• Student HAS-A Grade. Grade object is part of Student. Student cannot


calculate grades without Grade.

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

When to Use What?


• Use Inheritance when:
o Sharing common behavior i.e. Student types share common behavior
o There is a clear hierarchy
• Use Composition when:
o Objects work together
i.e. Grades are part of student data

12.3.3. Virtual Base Class


The concept of a virtual base class is crucial for resolving a specific problem in multiple
inheritance known as the "diamond problem".

[Link]. The Diamond Problem


The diamond problem arises when a class inherits from two classes, and those two
classes both inherit from a common base class. This creates a "diamond" shape in the
inheritance hierarchy. The ambiguity arises because the most derived class would have
two copies of the common base class's members, leading to confusion about which copy
to use.

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.

[Link]. Solution with Virtual Base Classes


Marking a base class as virtual during inheritance ensures that only one copy of the
base class is shared among all the derived classes in a multiple inheritance hierarchy,
effectively solving the diamond problem. This single shared instance of the virtual base
class is constructed only once.

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;
}
};

// Derived Class 1: inherits Person virtually


class Student : virtual public Person {
public:
// Constructor to initialize name and pass it to Person
Student(string n) : Person(n) {}
// Function to display student status
void displayStudentStatus() {
cout << name << " is a student." << endl;
}
};
// Derived Class 2: inherits Person virtually
class Employee : virtual public Person {
public:
// Constructor to initialize name and pass it to Person

307
Employee(string n) : Person(n) {}
void displayEmployeeStatus() {
cout << name << " is an employee." << endl;
}
};

// Derived Class that inherits from both Student and Employee


class WorkingStudent : public Student, public Employee {
public:
// Constructor to initialize name and pass it to the virtual base
//class (Person)and also to direct base classes (Student, Employee)
WorkingStudent(string n) : Person(n), Student(n), Employee(n) {}

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;
}

Note on Constructors with Virtual Base Classes:


When a class has a virtual base class, the constructor of the virtual base class is called
directly by the most derived class's constructor. Intermediate derived classes (like
Student and Employee in the example above) still need to call the virtual base class's
constructor in their initialization lists, but these calls are effectively ignored if the most
derived class also calls it. This ensures that the virtual base class is initialized only once.

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.

12.3.4. Virtual Functions and Polymorphism


Virtual functions are a cornerstone of polymorphism in C++. They enable dynamic
dispatch, meaning that the method that gets called is determined at runtime based on
the actual type of the object, rather than the type of the pointer or reference used to call
it.
• When a base class declares a member function as virtual, it signals to the compiler
that this function might be overridden by derived classes, and its specific
implementation should be resolved at runtime.
• This is essential for achieving runtime polymorphism, where a single interface
(defined in the base class) can be used to represent different implementations (in
derived classes).

Example:
class Animal {
public:
virtual void makeSound() {
cout << "Animal makes a sound" << endl;
}
};

class Dog : public Animal {


public:
void makeSound() override { // Using override keyword
cout << "Woof! Woof!" << endl;
}
};

class Cat : public Animal {


public:
void makeSound() override { // Using override keyword
cout << "Meow!" << 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;
}

Without the virtual keyword, myAnimal->makeSound() would always call


Animal::makeSound() regardless of whether myAnimal points to a Dog or a Cat
object (this is known as static dispatch or early binding). The virtual keyword enables late
binding, allowing the correct derived class function to be invoked.

[Link]. The override Keyword


The override keyword was introduced in C++11 to improve code safety and readability
when dealing with virtual functions.
• The override keyword explicitly indicates that a member function in a derived class
is intended to override a virtual function in a base class.
• Its primary benefit is to help catch errors during compilation. If a function marked
override does not actually match the signature (name, return type, parameters) of
any virtual function in the base class, the compiler will issue an error. This prevents
subtle bugs that can arise from typos or incorrect function signatures.

310
Example:
class Student {
public:
virtual void display() {
cout << "Displaying student information" << endl;
}
};

class Grades : public Student {


public:
// The override keyword ensures that this function correctly
// overrides a virtual function in the base class.
void display() override {
cout << "Displaying grades" << 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.

12.3.5. Abstract Classes and Pure Virtual Functions


Abstract classes and pure virtual functions are mechanisms to enforce an interface and
define a contract for derived classes.

[Link]. Pure Virtual Functions


A pure virtual function is a virtual function that has no definition (implementation) in
the base class. Instead, it is declared by assigning 0 to the function in the base class.

311
Syntax:
virtual ReturnType FunctionName(parameters) = 0;

Key characteristics of pure virtual functions:


• They make the base class abstract, meaning you cannot instantiate (create
objects of) the abstract base class directly.
• Derived classes must override all pure virtual functions inherited from their
abstract base class to be instantiated themselves. If a derived class fails to
override even one pure virtual function, it also becomes an abstract class.

[Link]. Abstract Classes


A class with at least one pure virtual function is called an abstract class.
Key characteristics of abstract classes:
• Cannot be instantiated directly: You cannot create objects of an abstract class.
• Intended to be a base class: Abstract classes serve as blueprints or interfaces for
other classes. They define a common interface that all their concrete (non-abstract)
derived classes must implement.
• Can have concrete (non-virtual) functions and data members: An abstract class
can have regular member functions with implementations and data members, in
addition to pure virtual functions.

Example:
// Abstract base class
class Student {
protected:
string name;
int studentID;
public:
Student(string n, int id) : name(n), studentID(id) {}

// Pure virtual function - makes Student an abstract class


virtual void display() = 0;

// A regular function that derived classes can use


void displayStudentInfo() {
cout <<"Name: " <<name <<", Student ID: " <<studentID << endl;

312
}
};

// Derived class - must override display() to be concrete


class Grades : public Student {
private:
char grade;
public:
// Constructor to initialize name, Student ID, and grade
Grades(string n, int id, char g) : Student(n, id), grade(g) {}

// Overriding the pure virtual function


void display() override {
displayStudentInfo(); // Call base class function
cout << "Grade: " << grade << endl;
}
};

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;
}

In this example, Student is an abstract class because of the virtual void


display() = 0; declaration. The Grades class provides an implementation for
display(), making it a concrete class that can be instantiated.

12.3.6 Protected Members and Inheritance


Access specifiers (public, private, protected) control the visibility and accessibility of class
members. protected members play a special role in inheritance.
• Protected members of the base class can be accessed directly by the derived
class but remain inaccessible to other parts of the program (i.e., outside the class
hierarchy).
• This provides a balance between private (accessible only within the class) and
public (accessible everywhere). protected members are typically used for data or
functions that are internal to the class and its derived classes, but not exposed to
the outside world.

313
Example:
class Student {
protected: // Accessible by derived classes
string name;
int studentID;
public:
void setStudentInfo(string n, int id) {
name = n;
studentID = id;
}
};

class Grades : public Student {


private:
char grade;
public:
void setGrade(char g) {
grade = g;
}
// Function to display student info and grade
void displayGrade() {
// Accessing protected members of the base class directly
cout << "Name: " << name << ", Student ID: " << studentID
<< ", Grade: " << grade << endl;
}
};

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.

[Link]. Friend Function


A friend function is a function that is not a member of a class but has access to the
class’s private and protected members. It is declared inside the class with the friend
keyword.

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);
};

// Friend function definition


void displayStudentDetails(Student s) {
// Can access private members 'name' and 'age' of Student
cout << "Name: " << [Link] << endl;
cout << "Age: " << [Link] << endl;
}

int main() {
Student student1("Mike Phiri", 24);
// Calls friend function
displayStudentDetails(student1);
return 0;
}

Here, displayStudentDetails() is declared as a friend of the Student class,


allowing it to directly access [Link] and [Link], even though they
are private members.

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
};

// Definition of Grade's member function


void Grade::displayStudentGrade(Student &s) {
// Can access private members 'name' and 'grade' of Student
cout << "Name: " << [Link] << endl;
cout << "Grade: " << [Link] << endl;
}

int main() {
Student student1("Tom Banda", 90);
Grade gradeObj;
[Link](student1);
return 0;
}

In this example, Grade is declared as a friend of Student. This grants


Grade::displayStudentGrade() (and any other member function of Grade) direct
access to [Link] and [Link], which are private members of
Student.

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

understand relationships between different classes and improving overall code


structure.
• By grouping related classes under a common base class, the codebase becomes
more logical and easier to navigate. This hierarchical structure mirrors real-world
classifications, enhancing clarity.

4. Maintenance Efficiency
• Changes made to the base class automatically affect all derived classes. This

reduces the effort and time required for maintenance.


• If a bug is found or an improvement is needed in a common functionality, fixing or
updating it in the base class propagates the change to all derived classes without
needing to modify each derived class individually.

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.

12.4.1. Understanding Polymorphism


Polymorphism is a core concept in OOP that enables objects of different types to be
treated as objects of a common type. This is achieved by allowing a single interface to
represent various types. The specific behavior executed depends on the actual type of
the object at the time of execution.
Polymorphism in C++ is primarily achieved through two main mechanisms:
• Compile-time Polymorphism (also known as Static Polymorphism or Early
Binding)
• Run-time Polymorphism (also known as Dynamic Polymorphism or Late
Binding)

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.

12.4.2. Types of Polymorphism in C++


In C++, polymorphism is mainly classified into two distinct types, each achieved through
different programming constructs:
a. Compile-time Polymorphism (Static Polymorphism)
b. Run-time Polymorphism (Dynamic Polymorphism)

[Link]. Compile-time Polymorphism (Static Polymorphism)


Compile-time polymorphism, also known as static binding or early binding, occurs
when the binding between a method call and its corresponding method implementation
is resolved at compile time. This means the compiler knows exactly which function will
be called before the program even starts running.

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.

Example: Function Overloading


#include <iostream>
#include <string>
using namespace std;

class Student {
public:
// Function to calculate total marks for integer values
int totalMarks(int assignment, int exam) {
return assignment + exam;
}

// Overloaded function to calculate total marks for float values


float totalMarks(float assignment, float exam) {
return assignment + exam;
}

// Another overloaded function: different number of parameters


int totalMarks(int assignment, int quiz, int exam) {
return assignment + quiz + exam;

320
}

// Another overloaded function: different types of parameters


string totalMarks(string studentName, int score) {
return studentName + " scored " + to_string(score) + " marks.";
}
};

int main() {
Student student;

int assignInt = 40, examInt = 50;


float assignFloat = 40.5f, examFloat = 50.3f;
int quizInt = 10;

// Calls int totalMarks(int, int)


cout << "Total Marks (int): " << [Link](assignInt,
examInt) << endl;

// Calls float totalMarks(float, float)


cout << "Total Marks (float): " << [Link](assignFloat,
examFloat) << endl;

// Calls int totalMarks(int, int, int)


cout << "Total Marks (int, int, int): " <<
[Link](assignInt, quizInt, examInt) << endl;

// Calls string totalMarks(string, int)


cout << "Student score report: " << [Link]("Alice",
95) << endl;

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.

Example: Operator Overloading


#include <iostream>
using namespace std;

class Student {
public:
int marks;

// Constructor to initialize marks


Student(int m) : marks(m) {}

// Overloading the + operator for Student objects


// This function defines what happens when you use the '+'
// operator between two Student objects.
// It returns a new Student object whose marks are the sum of the
// two operands.
Student operator+(const Student& s) {
//'this->marks' refers to the marks of the current object (s1 in main)
//'[Link]' refers to the marks of the object passed as argument (s2 in main)
return Student(this->marks + [Link]);
}

// Overloading the << operator for easy printing (friend function)


// This is often implemented as a friend function to allow access
// to private members and to enable cout << object; syntax.
friend ostream& operator<<(ostream& os, const Student& s) {
os << "Student Marks: " << [Link];
return os;
}
};

int main() {
Student s1(75); // Student object with 75 marks
Student s2(85); // Student object with 85 marks

// Adds marks of s1 and s2 using the overloaded '+' operator


Student s3 = s1 + s2;

322
// Output: 160
cout << "Total Marks after addition: " << [Link] << endl;

// Output: Student Marks: 160


cout << "Using overloaded << operator: " << s3 << endl;
return 0;
}

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.

Efficiency of Compile-time Polymorphism:


Compile-time polymorphism provides efficiency because the function or operator to be
called is determined during the compilation phase. This leads to faster execution as there
is no need for runtime lookup or decision-making.

[Link]. Run-time Polymorphism (Dynamic Polymorphism)


Run-time polymorphism, also known as late binding or dynamic binding, occurs when
the binding between a method call and its corresponding method implementation is
resolved at runtime. This means the decision about which function to call is made while
the program is executing, not during compilation.

Run-time polymorphism in C++ is primarily achieved through virtual functions and


abstract classes, and it is mainly accomplished using inheritance. It allows for greater
flexibility, as the behavior of a program can change dynamically based on the actual type
of the object being referenced.

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.

Example: Virtual Function


#include <iostream>
using namespace std:
// Base class
class Student {
public:
// Declaring displayGrade() as virtual
virtual void displayGrade() {
cout << "Base class: Grade not assigned yet." << endl;
}
};

// 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;
}
};

// Another derived class


class UndergraduateStudent : public Student {
public:
void displayGrade() override {
cout<<"Derived class:Grade for Undergraduate Student is B."<< endl;
}
};

int main() {
Student* s; // A pointer to the base class (Student)

324
GraduateStudent gs;
UndergraduateStudent ugs;

// Pointing base class pointer to a derived class object


s = &gs;
//Calls derived class method at runtime because displayGrade() is virtual

// Output: Derived class: Grade for Graduate Student is A.


s->displayGrade();
s = &ugs;
// Calls derived class method at runtime

// Output: Derived class: Grade for Undergraduate Student is B.


s->displayGrade();

// Direct object creation (no polymorphism here)


Student regularStudent;
// Output: Base class: Grade not assigned yet.
[Link]();
return 0;
}

In this example, even though s is a Student* pointer, when s->displayGrade() is


called, the C++ runtime determines the actual type of the object s is pointing to
(GraduateStudent or UndergraduateStudent) and calls the appropriate
displayGrade() implementation. This dynamic resolution is the essence of runtime
polymorphism.

b. Abstract Classes and Pure Virtual Functions


An abstract class in C++ is a class that contains at least one pure virtual function.
• Pure Virtual Function: A pure virtual function is a virtual function declared by
using the = 0 syntax in the base class. It has no implementation in the base class.

o Syntax:
virtual ReturnType FunctionName(parameters) = 0;

• Cannot be Instantiated: An abstract class cannot be instantiated directly. This


means you cannot create objects of an abstract class. Its purpose is to serve as a
base class for other classes.

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.

Example: Abstract Class


#include <iostream>
#include <string>
using namespace std;

// Abstract base class


class Student {
public:
// Pure virtual function - makes Student an abstract class
// Derived classes MUST implement this function
virtual void displayGrade() = 0;

// An abstract class can still have concrete (non-pure virtual) functions


void commonStudentInfo() {
cout << "This is common student information." << endl;
}
};

// Derived class 1: must implement displayGrade()


class UndergraduateStudent : public Student {
public:
// Implementing the pure virtual function
void displayGrade() override {
cout << "Undergraduate Student: Grade is B." << endl;
}
};

// Derived class 2: must implement displayGrade()


class PostgraduateStudent : public Student {
public:
// Implementing the pure virtual function
void displayGrade() override {
cout << "Postgraduate Student: Grade is A." << endl;
}
};

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;

// Calls derived class function at runtime


s1->displayGrade(); // Output: Undergraduate Student: Grade is B.
s2->displayGrade(); // Output: Postgraduate Student: Grade is A.

// Can call common (non-pure virtual) functions through base class pointer
s1->commonStudentInfo();//Output: This is common student information.

return 0;
}

In this example, Student is an abstract class because displayGrade() is a pure


virtual function. UndergraduateStudent and PostgraduateStudent are concrete
classes because they provide their own implementations for displayGrade(). This
structure enforces that any type of Student must have a way to display its grade, but
leaves the specific implementation details to the derived classes.

12.4.3. Virtual Destructor


A virtual destructor is a destructor in a base class that is declared with the virtual
keyword. It is a critical component in polymorphic class hierarchies, especially when
dealing with dynamic memory allocation.
• Ensures Proper Cleanup: A virtual destructor ensures that when an object of a
derived class is deleted through a pointer to a base class, the destructors of both
the base and derived classes are called in the correct order. The derived class
destructor is called first, followed by the base class destructor.

• Essential for Polymorphic Cleanup: This is absolutely essential in cases of


polymorphism to ensure proper cleanup of derived class resources. If a derived
class allocates memory or acquires other resources, its destructor is responsible for
releasing them.

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).

Example: Virtual Destructor


#include <iostream>
using namespace std;

class Base {
public:
// Virtual destructor
virtual ~Base() {
cout << "Base Destructor\n";
}
};

class Derived : public Base {


public:
// Overriding the destructor (implicitly virtual if base is virtual)
// Using 'override' keyword is good practice
~Derived() override {
cout << "Derived Destructor\n";
}
};

int main() {
// Dynamically allocate a Derived object and point to it with a Base pointer
Base* ptr = new Derived();

// Delete the object through the base class pointer


// Because ~Base() is virtual, both ~Derived() and ~Base() will be called.
delete ptr;

/*

328
Expected Output:
Derived Destructor
Base Destructor
*/

// If ~Base() was NOT virtual, only "Base Destructor" would be printed,


// potentially leading to memory leaks if Derived had allocated resources.

return 0;
}

[Link]. Virtual Destructor - Abstract Classes


Even for abstract base classes, it is crucial to declare the destructor as virtual. An
abstract base class can have a pure virtual destructor.
• Pure Virtual Destructor: A pure virtual destructor is declared with = 0; like other
pure virtual functions, but it must still have an implementation. The
implementation is typically provided outside the class definition. This is because
derived class destructors implicitly call their base class destructors, and even a pure
virtual destructor needs to be called.

Example: Virtual Destructor in Abstract Class


#include <iostream>
using namespace std;

class AbstractBase {
public:
// Pure virtual destructor - must have an implementation
virtual ~AbstractBase() = 0;
};

// Implementation of the pure virtual destructor


AbstractBase::~AbstractBase() {
cout << "AbstractBase Destructor\n";
}

class Derived : public AbstractBase {


public:
~Derived() override { // 'override' is good practice

329
cout << "Derived Destructor\n";
}
};

int main() {
// Dynamically allocate a Derived object through an AbstractBase pointer
AbstractBase* ptr = new Derived();

// Delete the object through the base class pointer


delete ptr;

/*
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.

12.4.4. Benefits of Polymorphism


Polymorphism is a cornerstone of robust and flexible object-oriented design, offering
numerous advantages:
1. Code Reusability
• Using polymorphism, we can reuse code and reduce duplication. It allows
methods to perform different tasks depending on the type of object.
• Instead of writing separate functions for each derived class, you can write a single
function that takes a base class pointer/reference, and it will work correctly with
any derived class object, thanks to dynamic dispatch. This promotes a cleaner
and more efficient codebase.

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,

which is essential for large-scale systems.


• When you need to introduce a new type (e.g., a Pentagon shape), you simply
create a new derived class and implement its specific behaviors. The existing
code that operates on the base class interface (e.g., a function that draws all
shapes) does not need to be modified, as it will automatically work with the new
type.

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.

12.5.1. Benefits of Encapsulation


Encapsulation allows for the following key advantages:
• Data Protection: Sensitive data can be hidden from outside interference and
misuse. By making data members private, direct external access is prevented,
safeguarding the object's internal state.

• 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.

• Improved Maintainability: By keeping related properties and methods together


within a class, it simplifies code management. Changes to internal implementation
details do not affect external code, as long as the public interface remains
consistent.

• Security: By controlling access to data, it prevents unauthorized or accidental


changes, enhancing the overall security of the program.

• Enhances Flexibility: Internal implementation can be changed without altering


external code that uses the class. This means you can refactor the internal
workings of a class without breaking other parts of the system that rely on its
public interface.

12.5.2. Components of Encapsulation


These components work together to create a well-encapsulated class, ensuring that
data is protected and accessed through controlled interfaces:
• Class: The fundamental unit that bundles data members and member functions.
• Access Specifiers: (private, public, protected) define the visibility and
accessibility of class members.
• Data Members: Variables within a class that hold the state or attributes of objects.
They are often declared as private to achieve data hiding.
o Example:
class Rectangle {
private:
double length; // private data member
double width; // private data member
public:
// public member functions (getters/setters)
};

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
}

// Getter for name (accessor)


string getName() const {//'const' indicates it doesn't modify the object
return name;
}

// Getter for grade (accessor)


int getGrade() const {// 'const' indicates it doesn't modify the object
return grade;
}
// Setter for grade (mutator) - provides controlled access and validation
void setGrade(int studentGrade) {

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

// Accessing and displaying student information using public methods


[Link]();

// Modifying the grade using setter (controlled access)


[Link](92); // Update grade
cout << "\nAfter updating grade:" << endl;
[Link]();

// Attempt to set an invalid grade (validation within setter)


[Link](105); // Invalid grade, message printed
[Link](); // Grade remains 92

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.

12.6.1. Importance of Abstraction


• Reduces Complexity: Abstraction helps in reducing complexity by modeling real-
world entities at a higher level, focusing on their relevant characteristics and
behaviors.
• Simplifies Interaction: It simplifies the interaction between objects by providing a
clean, public interface while hiding the complex internal implementation details.
Users of an object only need to know how to use its public methods, not how
those methods are implemented.
• Encourages Separation of Concerns: Abstraction encourages the separation of
concerns, where different parts of the system are responsible for different aspects.
This makes code easier to maintain, extend, and understand.

12.6.2. Achieving Abstraction in C++


Abstraction is mainly achieved in C++ using two primary mechanisms:
a. Using Classes (Basic Abstraction)
b. Using Abstract Classes and Pure Virtual Functions (Higher Level Abstraction)

[Link]. Using Classes (Basic Abstraction)


In basic abstraction, a class is designed to represent an entity with public methods that
provide meaningful actions without exposing internal details. The private and protected
access specifiers are used to hide the data and implementation.

Example: Abstraction Using Classes


#include <iostream>
#include <string>
#include <numeric> // For accumulate
Using namespace std;
// Class representing a student, hiding grade calculation details
class Student {

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
}

// Public method to display student's details (interface)


void displayInfo() const {
cout << "Name: " << name << ", Average Grade: " <<
calculateAverageGrade() << endl;
}
};

int main() {
Student student1("Jozy", 85, 90, 92);
[Link](); // Output: Name: Jozy, Average Grade: 89

// The user interacts only with public methods like displayInfo()


// and calculateAverageGrade().
// The internal details of 'grades' array and
//'calculateSumOfGrades()'are hidden.
return 0;
}

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.

• Derived Class Responsibility: Derived classes must provide concrete


implementations of these pure virtual functions to become instantiable.

Example: Abstraction Using Abstract Classes


#include <iostream>
#include <string>
#include <numeric>
using namespace std;

// Abstract base class for students


class StudentBase {
protected:
string name;
public:
// Constructor
StudentBase(string n) : name(n) {}

// Pure virtual function (abstract method). This forces derived


// classes to implement their own way of calculating the final grade.
virtual double calculateFinalGrade() = 0;

// Common method to display student's name and final grade


// This method uses the pure virtual function, demonstrating abstraction.

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;
}

// Implementation of the pure virtual function for RegularStudent


double calculateFinalGrade() override {
int sum = 0;
for (int i = 0; i < 3; ++i) {
sum += grades[i];
}
return sum / 3.0; // Simple average
}
};
// Derived class for project-based students
class ProjectStudent : public StudentBase {
private:
int projectGrade;
public:
ProjectStudent(string n, int pg) :
StudentBase(n), projectGrade(pg) {}

// Implementation of the pure virtual function for ProjectStudent


double calculateFinalGrade() override {
// Project students are graded only based on the project
return static_cast<double>(projectGrade);
}
};

340
int main() {
RegularStudent regularStudent("Chisomo", 78, 82, 85);
ProjectStudent projectStudent("Mphatso", 90);

// Display final grades using the common interface (displayFinalGrade)


// The actual calculation (calculateFinalGrade) is abstracted away.
[Link]();
// Output: Name: Chisomo, Final Grade: 81.6667
[Link]();
// Output: Name: Mphatso, Final Grade: 90

// Polymorphic usage:
StudentBase* s1 = &regularStudent;
StudentBase* s2 = &projectStudent;

s1->displayFinalGrade();// Calls RegularStudent's calculateFinalGrade()


s2->displayFinalGrade();// Calls ProjectStudent's calculateFinalGrade()

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.

12.6.3. Abstraction in Header Files


Abstraction is an Object-Oriented Programming (OOP) concept that hides
implementation details and exposes only essential features to the user.
• It allows the user to use functionality without knowing how it works internally.
• Abstraction is achieved in C++ using classes, functions, and header files.

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)

Structure of Abstraction with Header Files


Example: Student and Grades System

Step 1: Create a Header File (student.h)


#ifndef STUDENT_H
#define STUDENT_H

#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.

Step 2: Implementation File ([Link])

#include <iostream>
#include "student.h"
using namespace std;

// Student class implementation


Student::Student(int i, string n) {
id = i;
name = n;
}

void Student::display() {
cout << "ID: " << id << ", Name: " << name << endl;
}

// Grade class implementation


Grade::Grade(float m) {
marks = m;
}

char Grade::getLetterGrade() {
if (marks >= 80) return 'A';
else if (marks >= 60) return 'B';
else if (marks >= 50) return 'C';
else return 'F';
}

Step 3: Main Program ([Link])

#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

Advantages of Using Header Files for Abstraction


1. Hides Implementation
o Users only see class and function prototypes, not internal logic
2. Supports Modular Programming
o Each module (file) can be developed independently
3. Simplifies Maintenance
o Changing implementation does not affect main program
4. Reusability
o Header files can be included in multiple projects
5. Team Collaboration
o Developers can work on .cpp files while others use the interface

Activity 12.6
Explain the role of header files in abstraction.

12.7. Message Passing


Message Passing is a fundamental concept in OOP where objects communicate with
each other by calling methods/functions. It involves passing information (like data or
control messages) between objects to trigger specific behaviors.
• In C++, message passing typically occurs through function calls (or method
invocations) where one object sends a "message" by invoking another object's
method. This is how objects collaborate and interact to achieve the overall
program's goals.

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. Encapsulation of Data: Message passing inherently relies on encapsulation. It


ensures that one object does not access another object's internal state directly.
Instead, communication happens through the well-defined public interfaces
(methods) of the receiving object. This maintains data integrity and prevents
unintended side effects.

3. Polymorphism for Dynamic Behavior: Message passing often leverages


polymorphism. This enables different types of objects to respond to the same
message (method call) in their own unique way. For example, sending a draw()
message to different Shape objects will result in different drawing behaviors
(circle, square, etc.).

12.7.2. Key Concepts in Message Passing


1. Objects and Methods:
o Objects encapsulate data and behavior (methods).
o Methods are invoked to send messages to other objects.

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.

Message Passing – Example


#include <iostream>
#include <string>
using namespace std;

class Student {
private:
string name;
int grade;
public:
Student(string n) : name(n), grade(0) {}

// Method to update the student's grade (receives a message)


void setGrade(int g) {
grade = g;
cout << "Grade updated for " << name << ": " << grade << endl;
}

// Method to display student's current grade (for verification)


void displayCurrentGrade() const {
cout << name << "'s current grade is: " << grade << endl;
}
};

// Teacher class that interacts with Student objects

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

// Creating a teacher object


Teacher teacher;

// Teacher sends a message to Student to update grade


// The 'teacher' object is interacting with the 'student1' object.
[Link](student1, 85);

[Link](); // Updated grade: 85

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

12.8.1. Pure Virtual Functions


A pure virtual function is a virtual function with no implementation in the base class
and is declared using = 0.

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

12.8.2. Abstract Class


An abstract class is a class that contains at least one pure virtual function.

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;
}

virtual float calculateGrade() = 0; // Pure virtual


};

Derived Class Example – Exam Student

class ExamStudent : public Student {


private:
float examMarks;

public:
ExamStudent(int i, string n, float m) : Student(i, n) {
examMarks = m;
}

float calculateGrade() {
return examMarks;
}
};

Derived Class Example – Coursework Student

class CourseworkStudent : public Student {


private:
float courseworkMarks;

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

Interface Example – Grading Interface


class GradeInterface {
public:
virtual float getFinalGrade() = 0;
virtual char getLetterGrade() = 0;
};

Implementing the Interface – Student Class


class StudentGrade : public GradeInterface {
private:
float marks;

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';
}
};

12.8.3 Rules for Using Interfaces


1. An interface must contain only pure virtual functions
2. Interface classes should not contain data members
3. All interface functions must be declared public
4. A class implementing an interface must override all pure virtual functions
5. Objects of an interface class cannot be created
6. Interface pointers can point to derived class objects
7. A class can implement multiple interfaces (multiple inheritance)

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;
}

12.8.4 Importance of Interfaces


1. Supports Abstraction
• Shows what a class does, not how
• Hides implementation details

2. Enables Polymorphism
• Same interface, different behavior i.e. Same interface, different grading methods
GradeInterface* g;

3. Improves Code Flexibility


• Easy to change implementations without affecting code that uses the interface

4. Encourages Loose Coupling


• Classes depend on interfaces, not concrete implementations

5. Supports Multiple Inheritance Safely


• Avoids diamond problem since interfaces have no data members

6. Useful in Large Software Systems


• Common in:
o Device drivers
o Plug-in systems
o Frameworks
o APIs

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.

This program demonstrates all the core Object-Oriented Programming (OOP)


principles: Classes, Objects, Encapsulation, Inheritance, Polymorphism and
Abstraction

#include <iostream>
#include <string>
using namespace std;

// Base class representing a Bank Account


class BankAccount {
protected:
string accountHolder;
double balance;

public:
// Constructor
BankAccount(const string& holder, double initialBalance)
: accountHolder(holder), balance(initialBalance) {}

// Getter for balance


double getBalance() const {
return balance;
}

// Virtual function to display account information

352
virtual void displayAccountInfo() const {
cout << "Account Holder: " << accountHolder
<< "\nBalance: MKW" << balance << endl;
}

// Virtual function for deposit


virtual void deposit(double amount) {
balance += amount;
cout << "Deposited: MKW" << amount << endl;
}

// Virtual function for withdrawal


virtual void withdraw(double amount) {
if (amount <= balance) {
balance -= amount;
cout << "Withdrawn: MKW" << amount << endl;
} else {
cout << "Insufficient funds!" << endl;
}
}
};

// Derived class representing a Savings Account


class SavingsAccount : public BankAccount {
private:
double interestRate; // Interest rate in percentage

public:
// Constructor with interest rate
SavingsAccount(const string& holder, double initialBalance, double
rate): BankAccount(holder, initialBalance), interestRate(rate) {}

// Overriding displayAccountInfo to include interest rate


void displayAccountInfo() const override {
BankAccount::displayAccountInfo(); // Call base version
cout << "Interest Rate: " << interestRate << "%" << endl;
}

// Overriding deposit to add interest


void deposit(double amount) override {
BankAccount::deposit(amount); // Base deposit
// Add interest to balance
balance += balance * (interestRate / 100.0);
}
};

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

// Display account information (demonstrates polymorphism)


[Link]();
cout << "--------------------------" << endl;
[Link]();
cout << "--------------------------" << endl;

// Perform transactions
[Link](500.0);
[Link](200.0);
cout << "--------------------------" << endl;

[Link](1000.0); // Will also add 5% interest


[Link](300.0);

return 0;
}

This program demonstrates basic OOP concepts:


1. Encapsulation
• Wrapping of data (like accountHolder, balance) and the methods (deposit,
withdraw) into a single unit (class).
• How it's used:
o Data members like balance are protected or private, preventing
direct access.
o Access is controlled using public methods like getBalance().

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).

class SavingsAccount : public BankAccount

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.

• How it's used:


o Users interact with a simple interface (deposit, withdraw) without knowing
how balance or interest is calculated internally.
o Functions provide an abstraction over internal calculations.

5. Objects and Classes


o Class: Blueprint for creating objects.

o Object: Instance of a class.


• How it's used:
o Two objects are created:
▪ account1 from BankAccount
▪ account2 from SavingsAccount

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.

You've gained an understanding of object-oriented programming principles and the


advantages they offer in software development. In the upcoming unit, we'll explore the
templates in C++.

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.

13.1. Understanding Templates


Templates are a cornerstone of modern C++ programming, enabling developers to write
highly generic and reusable code. Instead of writing multiple functions or classes for
different data types, templates allow you to define a single blueprint that works for any
data type.

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.

There are two primary types of templates in C++:


1. Function Templates
2. Class Templates

13.1.1. Function Templates


A function template allows us to create a single function definition that can operate on
different data types. It essentially specifies how a function can be constructed to perform
a task on multiple data types without needing to overload it for each 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.

Syntax for Function Templates:


template <class T> // or template <typename T>
return_type function_name(T arg1, T arg2, ...) {
// function body that uses 'T' as a data type
}
• template <class T> or template <typename T>: This is the template

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.

[Link]. The swap Function Template Example


Consider the common task of swapping the values of two variables. Without templates,
you would need to write separate functions for each data type:

Traditional (Non-Templated) swap functions:


// For swapping integers
void swap(int &a, int &b) {
int temp = a;
a = b;
b = temp;
}

// For swapping strings


void swap(string &a, string &b) {

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.

Using a Function Template for swap:


The difference in these two functions is only the type of the variables being swapped.
The core logic remains the same. This common logic can be captured with one template
function:
template<class T> // Declares 'T' as a generic type parameter
void swap(T &a, T &b) { // 'T' is used as the type for
parameters and local variable
T temp = a;
a = b;
b = temp;
}

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.

[Link]. Function Templates – Example I: swapValues


Let's see another example demonstrating the power of function templates with a
swapValues function:

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;

template <typename T>


T findMax(T grade1, T grade2) {
// Uses the ternary operator to return the larger of the two
values
return (grade1 > grade2) ? grade1 : grade2;
}

int main() {
// Finding maximum of two integers
int grade1 = 85, grade2 = 90;
cout << "Maximum (int): " << findMax(grade1, grade2) <<endl;

// Finding maximum of two doubles


double grade3 = 87.5, grade4 = 92.3;
cout <<"Maximum (double): "<< findMax(grade3, grade4)<<endl;

// Finding maximum of two floats


float f1 = 75.2f, f2 = 78.9f;
cout << "Maximum (float): " << findMax(f1, f2) << endl;
// Finding maximum of two characters (compares ASCII values)
char c1 = 'X', c2 = 'A';
cout << "Maximum (char): " << findMax(c1, c2) << endl;
return 0;
}

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.

Example: Overloading Function Templates


#include <iostream>
#include <string>
using namespace std;

// First function template: prints a single value


template <class T>
void print(T a) {
cout << a << endl;
}

// Second function template: prints a value 'n' times


template <class T>
void print(T a, int n) { // Different parameter list
for (int i = 0; i < n; i++) {
cout << a << " ";
}
cout << endl;
}

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"

// Calls the second template: print(T a, int n)


print(455, 3); // T is int, prints 455 three times
print("world", 2); // T is const char*, prints "world" two times
// What if we try to call with mixed types that don't fit?
// print("hello", 3.0); // ERROR: No matching function for
// call to 'print(const char [6], double)'

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.

13.1.3. Multiple Arguments in Function Templates


Templates are not limited to a single type parameter. You can define a template that
accepts multiple parameters of different types. This is incredibly useful when a function
needs to work with mixed data types.

Syntax:
template <class T1, class T2, ..., class Tn> // or using typename
return_type function_name(T1 arg1, T2 arg2, ..., Tn argn) {
// function body
}

Example: Sum of two different numbers


#include <iostream>
using namespace std;

template <class T, class U> // Two type parameters: T and U


T sum(T a, U b) {
// Cast 'b' to type 'T' for consistency in the return type.
// This ensures the return type is consistent with the first
// argument's type.
return a + static_cast<T>(b);
}
int main() {
// T is int, U is double (5.5 is double literal by default)
// Result will be an int (5) because 'b' is cast to 'int'
cout << "sum(4, 5.5): " << sum(4, 5.5) << endl;
// Output: 9 (4 + 5 = 9, 0.5 truncated)
// T is float, U is int
// Result will be a float (8.4) because 'b' is cast to 'float'
cout << "sum(5.4f, 3): " << sum(5.4f, 3) << endl; // Output: 8.4
// T is double, U is int
cout << "sum(10.2, 7): " << sum(10.2, 7) << endl; // Output: 17.2

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.

13.1.4. Class Templates


Just as function templates allow generic functions, class templates allow you to define
generic classes that can operate on different types of data while still using the same
underlying code structure.
• A class template allows defining a generic class that can operate on different types
of data.
• This is particularly useful when you want to create data structures (like a list, stack,
queue, or a pair) that need to work with various types of elements. Instead of writing
a separate IntStack, FloatStack, StringStack, etc., you can write a single
Stack class template.

The syntax for class templates is similar to that of function templates, but the template
header precedes the class definition.

Syntax for Class Templates:


template <typename T> // or template <class T>
class ClassName {
T data; // Data member of generic type T
public:
ClassName(T arg) : data(arg) {} // Constructor
void display(); // Member function declaration
};

// Definition of a member function outside the class template


template <typename T>
void ClassName<T>::display() { // Note: ClassName<T> is used here
cout << data << endl;
}

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.

Creating Objects of a Class Template:


o You create objects of a template class by specifying the actual data type
in angle brackets (<>) after the class name:
ClassName<DataType> objName;

[Link]. Class Templates - Example: Student Class with Generic Grade


Let's consider an example of a Student class that can store a student's grade,
regardless of whether the grade is an int, float, or even a double.
#include <iostream>
#include <string>
using namespace std;

template <typename T> // Class template for Student


class Student {
private:
T grade; // Data member of generic type T

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.

13.1.5. Template Specialization


Template specialization allows you to define a special version of a template for a
specific type. This is useful when the generic template's implementation is not optimal
or correct for a particular data type, or when you want to customize the behavior of a
template for certain data types.

When the compiler encounters a template instantiation request for a specialized type, it
will use the specialized version instead of the generic template.

Syntax for Template Specialization (Full Specialization):


template <> // Empty angle brackets indicate full specialization
class ClassName<SpecificType> {
// Specialized version of the class for SpecificType
// You can define completely different members and logic here.
};

[Link]. Template Specialization - Example


Consider the Student class template from before. What if we want to handle letter
grades (e.g., 'A', 'B', 'C') differently from numeric grades? The generic Student<T>
works well for numbers, but for string (representing letter grades), we might want a
different display message or even different internal logic.
#include <iostream>
#include <string>
using namespace std;
// Generic Class Template
template <typename T>
class Student {
private:
T grade;
public:
Student(T g) : grade(g) {}

368
void displayGrade() {
cout << "Student's Grade: " << grade << endl;
}
};

// Template Specialization for string type


template <> // Indicates full specialization
class Student<string> { // Specializing for string
private:
string grade; // Data member specifically for string grade
public:
Student(string g) : grade(g) {}
void displayGrade() {
cout << "Student's Grade (Letter): " << grade << endl;
}
};
int main() {
// Uses the generic template for int
Student<int> student1(85);
[Link](); // Output: Student's Grade: 85

// Uses the specialized template for string


Student<string> student2("A");
[Link](); // Output: Student's Grade (Letter): A

// Uses the generic template for float


Student<float> student3(78.5f);
[Link](); // Output: Student's Grade: 78.5

return 0;
}

In this example, when Student<string> is instantiated, the compiler uses the


specialized version of the Student class, which has a customized displayGrade()
method. For Student<int> and Student<float>, the generic template is used.

13.1.6. Templates with Multiple Parameters


Just like function templates, class templates can also be defined to accept multiple data
types by specifying more than one type parameter in the template declaration. This
allows for creating generic classes that can store or operate on different combinations of
types.

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;

template <typename T1, typename T2> // T1 for name, T2 for grade


class Student {
private:
T1 name;
T2 grade;
public:
Student(T1 n, T2 g) : name(n), grade(g) {}
void displayInfo() {
cout <<"Student: " << name <<", Grade: " <<grade<< endl;
}
};

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.

13.1.7. Template Functions in Classes (Member Function Templates)


You can also define template functions inside non-template classes, making only the
function generic, not the entire class. This is useful when a specific member function
needs to operate on different data types, while the rest of the class remains non-
templated.

Example: Student Class with a Templated Function for Comparing Grades


Let's extend the Student class to have a function template for comparing two grades.
The Student class itself is not a template; only its compareGrades member function
is.

#include <iostream>
#include <string>
Using namespace std;

class Student { // This is a regular (non-template) class


private:
string name;
float grade; // Student's own grade is a float
public:
Student(string n, float g) : name(n), grade(g) {}

// Member function template: compares two grades of a generic type T


template <typename T>
T compareGrades(T g1, T g2) {
return (g1 > g2) ? g1 : g2;
}

void displayInfo() {
cout << "Student: " << name << ", Grade: " << grade << endl;
}
};

371
int main() {
Student student("Charlie",87.0f); // Create a regular Student object

int g1_int = 85;


int g2_int = 90;
float g3_float = 88.5f;
double g4_double = 91.2;

// Using the compareGrades function template with different types


cout << "Max grade (int): " << [Link](g1_int,
g2_int) << endl;
cout << "Max grade (float): " << [Link](g3_float,
g2_int) << endl; // g2_int is promoted to float
cout << "Max grade (double): " << [Link](g4_double,
static_cast<double>(g1_int)) << endl; // Explicit cast for clarity

[Link](); // Display info of the 'student' object itself

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.

13.1.8 Argument Deduction


Argument deduction is a feature of C++ templates that allows the compiler to
automatically determine the data type of template parameters based on the
arguments passed to a function or constructor. This means the programmer does not
need to explicitly specify template arguments in many cases.

Why Argument Deduction is Needed


Argument deduction:
• Makes code shorter and cleaner
• Reduces programming errors
• Improves readability
• Allows templates to behave like normal functions

372
Basic Template Without Argument Deduction

#include <iostream>
using namespace std;

template <class T>


T add(T a, T b) {
return a + b;
}

int main() {
cout << add<int>(5, 10); // Explicit type
return 0;
}

• Here, the programmer explicitly specifies <int>

Template Argument Deduction


Template argument deduction allows the compiler to deduce the template type
automatically from function arguments.

Example
#include <iostream>
using namespace std;

template <class T>


T add(T a, T b) {
return a + b;
}

int main() {
cout << add(5, 10); // Compiler deduces T as int
cout << add(2.5, 3.5); // Compiler deduces T as double
return 0;
}

• For add(5, 10) → T = int


• For add(2.5, 3.5) → T = double

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;
}

Argument Deduction with Multiple Parameters


• Argument deduction works only when all parameters match the same type.
template <class T>
T multiply(T a, T b) {
return a * b;
}

int main() {
cout << multiply(3, 4); // T = int
cout << multiply(2.5, 4.0); // T = double
return 0;
}

Argument Deduction Failure


Argument deduction fails when:
• Function arguments have different data types
• The compiler cannot determine a single template type
template <class T>
T add(T a, T b) {
return a + b;
}

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);

2. Use Multiple Template Parameters


template <class T1, class T2>
auto add(T1 a, T2 b) {
return a + b;
}

Argument Deduction with References


• The compiler deduces the actual type, ignoring reference symbols.
template <class T>
void show(T& x) {
cout << x << endl;
}

int main() {
int a = 10;
show(a); // T deduced as int
return 0;
}

Argument Deduction with const


• const is ignored during type deduction unless explicitly required.
template <class T>
void display(const T& x) {
cout << x << endl;
}

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;

template <class T>


class Box {
public:
T value;
Box(T v) {
value = v;
}
};

int main() {
Box b(100); // T deduced as int
Box c(3.14); // T deduced as double
return 0;
}

Limitations of Argument Deduction


• Does not work with return types alone
• Cannot deduce types if arguments are ambiguous
• Sometimes requires explicit template arguments

13.1.9. Advantages of Templates


Templates are a cornerstone of modern C++ development due to the significant
advantages they offer:
i. Code Reusability:
o Templates allow writing generic code that works for multiple data types,
avoiding redundancy. This is the primary benefit, as it means less code to
write, debug, and maintain.
o Instead of duplicating code for different types, you write it once in a generic
form.

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++?

13.2. Standard Template Library (STL)


The Standard Template Library (STL) in C++ is a powerful library of generic classes
and functions that allows programmers to use well-defined data structures and
algorithms. It is a prime example of how templates are used to provide a rich set of
reusable components.
• The STL contains many templates for useful algorithms and data structures, which
are highly optimized and thoroughly tested.
• It is a key component of modern C++ programming, providing reusable
components and saving significant development time by offering ready-to-use
implementations for common operations like sorting, searching, and managing
collections of data.

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};

• deque (Double-Ended Queue): A dynamic array that allows efficient insertion


and deletion at both ends (front and back). It also provides random access.
o Example: deque<char> chars = {'a', 'b', 'c'};

• 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};

ii. Associative Containers:


These containers store data in key-value pairs or unique elements, typically in a sorted
or hashed order, allowing for very efficient lookup, insertion, and deletion based on keys.
• map: Stores elements in key-value pairs, where keys are unique and sorted.
Each key maps to exactly one value.
o Example: map<string, int> ages = {{"Alice", 30}, {"Bob", 25}};

• 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};

• multimap: Similar to map but allows duplicate keys.


o Example: multimap<string, int> scores = {{"Alice", 85},
{"Bob", 90}, {"Alice", 92}};

• multiset: Similar to set but allows duplicate elements.


o Example: multiset<int> numbers_with_duplicates = {10, 20,
10, 30};

• Unordered Associative Containers (C++11 onwards): unordered_map,


unordered_set, unordered_multimap, unordered_multiset. These
use hash tables for storage, providing average constant-time complexity for
operations, but elements are not sorted.

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]();

• priority_queue: A queue where the highest priority element is always at the


front. Elements are ordered based on their value (by default, largest value has
highest priority).
o Example: priority_queue<int> pq; [Link](5); [Link](10);

[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.

Example of using an iterator:


#include <iostream>
#include <vector>
using namespace std;

int main() {
vector<int> numbers = {10, 20, 30, 40, 50};

// Create an iterator pointing to the beginning of the vector


vector<int>::iterator it = [Link]();

// Traverse the vector using the iterator


while (it != [Link]()) {
cout << *it << " "; /* Dereference the iterator to
access the element */
++it; // Move to the next element
}
cout << endl; // Output: 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.

Some common algorithms include:


• sort: Sorts elements in a given range (e.g., a vector) in ascending order by
default.
o Example: sort([Link](), [Link]());

• 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);

• reverse: Reverses the order of elements within a specified range.


o Example: reverse([Link](), [Link]());

• count: Counts occurrences of a specific value in a container within a given range.


o Example: int occur = count([Link](), [Link](), 20);

• for_each: Applies a given function object to each element in a range.

• transform: Applies a function to elements in a range and stores the results in


another range.

• accumulate (from <numeric>): Calculates the sum of elements in a range.

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};

cout << "Original vector: ";


for (int num : numbers) {
cout << num << " ";
}
cout << endl;

// Sort the vector using sort algorithm


sort([Link](), [Link]());
// Sorts from beginning to end

cout << "Sorted vector: ";


for (int num: numbers) {
cout << num << " ";
}
cout << endl; // Output: 10 20 30 40 50

return 0;
}

[Link]. Additional STL Features


Beyond the core components, STL also incorporates other powerful features that
enhance its flexibility and expressiveness:
i. Functors (Function Objects):
o A functor is an object that can be called as if it were a function. It's an
instance of a class that overloads the function call operator (operator ()).
o Functors are used extensively in STL algorithms to provide custom
operations (e.g., custom comparison logic for sorting, or specific predicates
for searching). They can maintain state, which regular functions cannot.

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++?

13.3. Trending and Emerging Technologies in C++


C++ continues to evolve and remain highly relevant in many cutting-edge domains due
to its unparalleled performance, low-level control, and strong community support.
Trending and emerging technologies in C++ often revolve around its integration with
modern software development practices and its use in high-performance computing.
1. Concurrency and Parallelism:
o Modern C++ standards (especially C++11, C++14, C++17, and C++20) have
significantly enhanced support for concurrency and parallelism. C++20
introduced coroutines, which enable more efficient handling of asynchronous
tasks and non-blocking I/O, leading to highly responsive applications.
o The standard library now includes robust features for multi-threading
(<thread>, <mutex>, <future>), atomic operations (<atomic>), and
parallel algorithms (<execution>).
o Libraries like Intel's Threading Building Blocks (TBB) and OpenMP are
widely used for developing parallel applications that leverage multi-core
processors effectively.

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.

3. Embedded Systems and IoT (Internet of Things):


o C++ continues to dominate in the realm of embedded systems and IoT
devices. Its ability to provide low-level memory control, direct hardware
access, and exceptional efficiency makes it ideal for resource-constrained
environments.
o Microcontrollers, real-time operating systems (RTOS), and edge
computing devices increasingly leverage modern C++ standards for better
performance, safety, and maintainability in applications ranging from smart
home devices to industrial automation.

4. C++ and WebAssembly (Wasm):


o WebAssembly (Wasm) is a low-level bytecode format that allows code
written in languages like C++ to run in web browsers at near-native speeds.
This technology is expanding C++'s use case to web development, enabling
complex, high-performance applications to run directly in the browser without
plugins.
o Projects like Emscripten are instrumental in compiling C++ code to
WebAssembly, bringing demanding applications (e.g., games, CAD software,
video editors) to the web platform with significant performance benefits.

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.

6. C++ in Blockchain and Cryptography:


o Due to its efficiency, performance, and control over system resources, C++ is
a popular language for developing blockchain platforms (e.g., Bitcoin Core,
Ethereum, Hyperledger Fabric). The demanding computational
requirements of cryptographic operations and distributed ledger technologies
make C++ an ideal choice.
o Emerging cryptographic algorithms and secure systems are often
implemented in C++ for maximum speed and security, ensuring the integrity
and performance of decentralized applications.

7. Modern C++ and Performance Optimization:


o The C++ language itself is continuously evolving with new standards (C++11,
C++14, C++17, C++20, and the upcoming C++23). These standards focus on
improving safety, simplicity, and performance.
o Features like concepts (for compile-time type checking and cleaner template
error messages), ranges (for more expressive and efficient algorithms), and
modules (for faster compilation and better code organization) are
transforming how C++ is written.
o Memory-safe coding practices, including the widespread adoption of smart
pointers (unique_ptr, shared_ptr) and robust resource management
techniques (RAII - Resource Acquisition Is Initialization), are becoming

386
standard in large-scale software development, reducing common pitfalls like
memory leaks.

8. C++ in Cloud-Native and Microservices:


o While not as commonly associated with web services as languages like Java
or Python, C++ is gaining ground in high-performance, low-latency
microservices and cloud-native applications that require extreme
scalability and speed.
o For services where every millisecond counts (e.g., financial trading systems,
real-time analytics), C++ offers a significant performance advantage.
o Tools like gRPC (Google's Remote Procedure Call framework) integrate
seamlessly with C++ to provide efficient service-to-service communication in
cloud environments, enabling robust and high-throughput distributed
systems.

9. C++ and Data Science:


o While Python is dominant in data science, C++ plays a crucial role in the
underlying libraries and for performance-critical components. Data-centric
C++ libraries like xtensor (for N-dimensional arrays) and Armadillo (for
linear algebra) are becoming popular for numerical computing.
o This brings C++ into the data science field, particularly in areas requiring
significant performance optimization, such as high-frequency trading,
large-scale scientific simulations, and complex data processing pipelines.

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.

14.1.1. Schemes of File Organization


File organization mainly refers to the logical arrangement of data in a file system. In order
to be able to retrieve a target record from a file, it is preferred to be arranged in some
defined or proper way. It is necessary to organize data records in a particular pattern. The
proper arrangement of records within a file is known as file organization. There are
various ways in which records in a file can be stored. Files are presented to the application
as a stream of bytes and at the end, it contains an EOF (end of file) mark.

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.

[Link]. Direct or Random-Access File


Records are not usually stored in sequence but randomized to individual storage
positions. To get the address of the record using a key, there must be some relationship
between the key and the address. The address for record storage and retrieval is
computed by using a ‘hashing’ algorithm. You retrieve the record directly with the help of
the key and the hash function, without considering the position of the record in the file,
the organization is known as direct access file organization.

[Link]. Indexed Sequential File


Records are stored sequentially but the index file is prepared for accessing the record
directly. An index file contains records ordered by a record key. The record key uniquely
identifies the record and determines the sequence in which it is accessed with respect to
other records.

[Link]. Multi-indexed file


In a multi-indexed file, the data file is associated with one or more logically separated
index files. Inverted files and multi-list files are examples of multi-indexed files.

14.1.2. Factors Affecting File Organization


File organization describes a way in which the records are stored in a file. The objective
of file organization is to provide predefined and efficient means for the: Record storage
Retrieval and Update. The factors that mainly affect file organization are the following:
1. Storage device: - The way data is arranged in a file depends on the storage
device. The magnetic tape is suitable for sequential organization. Direct access
devices such as hard disks are suitable for random access file 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.

4. Mode of retrieval/update of record: - The mode of retrieval or update may be


real-time or batched. In real-time retrieval, the response time for any query should
be minimum.

14.1.3. Factors Involved in Selecting File Organization


Choosing a specific file organization depends on the nature of data and the algorithm
used in the application. The following are the criteria used to choose file organization:
1. Speed: - Rapid access to a single record or a collection of records
2. Operations: - Convenience of update, that is, addition, modification, or deletion of
records
3. Capacity: - Efficiency of storage
4. Size: - Volume of transaction
5. Integrity: - Redundancy, being the method of ensuring data integrity
6. Security: Special backup and recovery processes must exist to prevent exposure
to the risks of loss of accuracy

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)

14.2.1. File Stream Data Types


There are three steps to use files: opening, reading/writing and closing. In C++, this is
achieved using file stream data types (objects) There are three different file stream data
types:
• ofstream – for opening file for writing (output file)
• ifstream – for opening file for reading (input file)
• fstream – for opening file for both reading and writing (input & output)
To use file stream data types the fstream header file must be included in the program

[Link]. File Stream Declaration


The three file stream types can be used to declare (instantiate) objects that later can be
used to open and work with the file. This is how to declare:
ifstream inFile;
ofstream outFile;
fstream inOutFile;

[Link]. Primitive Functions


There are several ways of reading (or writing) the text from (or to) a file, however, all of
them share a common approach as follows:
1. Open the file
2. Read (or write) the data
3. Close the file

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);

The file name can be initialized while creating an object.

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]”);

[Link]. File Opening Modes


The open() member function defines the mode in which the file should be opened.
1. ios::app
Append mode. If the file already exists, its contents are preserved and all output is
written to the end of the file. By default, this flag causes the file to be created if it
does not exist.

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

14.2.3. Closing Files


After reading from or writing to a file, the file must be closed. The file stream object has a
close() function for this purpose.
[Link]();
[Link]();

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.

14.3.1. Reading from a File


To read a file, instream must be declared first and attached to a disk file before using that
instream. To declare instream use ifstream. Ifstream is for “input file stream” as shown
below:
ifstream variable;
[Link](filepath);

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”;
}

14.3.2. Checking end of file


We can read data from the file byte by byte, word by word, or line by line. Whichever way,
we need to know when to stop reading from the file i.e. whether the end of the file is
reached. To do so, you can loop thru the file content reading a chunk of data at a time
until eof is reached as shown below:
while(!in_file.eof())
in_file>>line; //Read a chunk of data (a line)

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;
}

14.3.4. Copying Files


You can copy a file by iterating through the source (original) file and writing line by line to
the new file. This is done by using a loop. The file content can also be copied to another
file without using a loop, you can use rdbuf() function instead, which reads all data at
once from original file. Remember to include stdio.h header when using rdbuf()
function.
ifstream infile(“[Link]”);
ofstream outfile(“[Link]”);
out_file<<[Link]();

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.

14.4.1. Opening Binary Files


When working with binary files, it’s crucial to specify the ios::binary flag to ensure
proper handling of binary data.

Example:

ofstream outfile(“[Link]”, ios::binary);

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

14.4.3. Reading from Binary Files


A binary file can be read using ifstream’s read()function. Use the read() method to
read binary data. Ensure proper data type and size match for reading.
Syntax:
[Link](reinterpret_cast<char*>(&variable),
sizeof(variable));
read(char *address_of_buffer, int number_of_bytes);

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.

14.5.1. File Stream Initialization


Begin by initializing a file stream (fstream) object with the appropriate file mode,
including both input and output flags.

Example:

fstream file("[Link]", ios::in | ios::out |


ios::binary);

14.5.2. Setting the File Position


Use seekg() for reading and seekp() for writing to set the file position.

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.

14.5.3. Reading at a Specific Position


After setting the file position, use the read() method to retrieve data from the specified
location.

407
Example:
[Link](10, ios::beg);//Move to the 11th byte from the beginning
int data;
[Link](reinterpret_cast<char*>(&data), sizeof(int));

14.5.4. Writing at a Specific Position


Similarly, after setting the file position, use the write() method to modify or add data
at the specified location.

Example:
[Link](20, ios::beg); // Move to the 21st byte from the beginning
int newData = 42;
[Link](reinterpret_cast<const char*>(&newData),sizeof(int));

Example: C++ Program to demonstrate 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;
}
// 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.

[Link]. tellg() - Get Input File Position


- tellg() returns the current get position (read position) in the file.
- Example:
streampos currentPosition = [Link]();

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.

[Link]. tellp() - Get Output File Position


- tellp() returns the current put position (write position) in the file.
- Example:
streampos currentPosition = [Link]();

[Link]. Combined use with seekg() and seekp()


These methods (tellg() and tellp() ) are often used in combination with seekg()
and seekp() to retrieve and set file positions.

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;
}

// Get the current position


streampos initialPosition = [Link]();

// 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 using tellp()


[Link](9 * sizeof(int), ios::beg);

// Read the value at this position


int readValue;
[Link](reinterpret_cast<char*>(&readValue), sizeof(int));

cout << "Value at position 10: " << readValue <<endl;

// Move back to the initial position


[Link](initialPosition);

[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

15.1.1 Types of Program Documentation


Documentation produced during a software project can be divided into two categories:
i. Process Documentation
These documents record the process of development and maintenance. Examples
include: - plans, schedules (Gantt charts) and process quality documents

ii. Product Documentation


These documents describe the product that is being developed Can be divided
into two sub categories
• System Documentation: - Used by engineers developing and maintaining
the system
• User Documentation: - Used by the people using the system

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.

Characteristics of Process Documentation


The major characteristic of process documentation is that most of it becomes outdated.
Plans may be drawn up on a weekly, fortnightly or monthly basis. Progress will normally
be reported weekly. Memos record thoughts, ideas and intentions which inevitably
change.

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.

ii. System installation document: - It is for system administrators. This document


provides details of how to install the system in a particular environment. It should
contain a description of the files included in the system and the minimal hardware
configuration required.

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.

v. System administrator’s guide: - System administrator’s guide should be


provided for some types of system such as command and control systems. This
should describe the messages generated when the system interacts with other
systems and how to react to these messages. Normally they are used by system
administrators.

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?

15.2 Document Structure


The document structure is the way in which the material in the document is organized into
chapters and, within these chapters, into sections and subsections. Document structure
has a major impact on readability and usability and it is important to design this carefully
when creating documentation. Structuring a document properly also allows readers to
find information more easily. The following are minimal structuring guidelines that should
be followed:
i. All documents should have a cover page which identifies the project, the
document, the author, the date of production, the type of document, the intended
recipients of the document, and the confidentiality class of the document.

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.

iii. If a document includes extensive detailed or reference information, it should


include an index.

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.

15.2.1 Components of software user document


Components to be included in a software user document include the following:
• Identification data: - title and identifier that uniquely identifies the document.
• Table of contents: - Chapter/section names and page numbers.
• List of illustrations: - Figure numbers and titles
• Introduction: - purpose of the document and a brief summary
• Information for use of the documentation: - Suggestions for different readers on
how to use the documentation effectively
• Concept of operations: - explain conceptual background to the use of the software.
• Procedures: - Directions on how to use the software
• Information on software commands: - Description of each of the commands
• Error messages and problem resolution: - Description of the errors and recovery
• Glossary: Definitions of specialized terms used.
• Related information sources: References or links for additional information
• Navigational features: Allow readers to move around the document.
• Index: - A list of key terms and the pages where these terms are referenced.
• Search capability: - In electronic documentation, a way of finding specific terms in
the document.

15.2.2 Document Writing style


Good documentation requires good writing. Good written document must be written,
read, criticized and then rewritten until a satisfactory document is produced. Technical
writing is a craft rather than a science but some broad guide-lines about how to write well
are:
• Use active rather than passive tenses
• Use grammatically correct constructs and correct spelling
• Do not use long sentences which present several different facts

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

Documents should be inspected in the same way as programs. During a document


inspection, the text is criticized, omissions pointed out and suggestions made on how to
improve the document. You can also use grammar checkers which are incorporated in
word processors. These checkers find ungrammatical or clumsy uses of words. They
identify long sentences and paragraphs and the use of passive rather than active tenses.
They help identify phrases which could be improved.

Activity 15.2
What are the elements of a technical document?

15.3 Document Preparation


Document preparation is the process of creating a document and formatting it for
Publication.

15.3.1 Document preparation stages


The document preparation process can be split into 3 stages namely:
i. Document creation
ii. Document polishing
iii. Document production

420
Figure 15.1: Document preparation process (Adapted from Sommerville, 2015, ch
30, p. 17)

Stage 1: Document Creation


The initial input of the information in the document. This is supported by word processors
and text formatters, table and equation processors, drawing and art packages.

Stage 2: Document polishing


This process involves improving the writing and presentation of the document to make to
make it more understandable and readable. This involves finding and removing spelling,
punctuation and grammatical errors, detecting clumsy phrases and removing redundancy
in the text. The process may be supported by tools such as on-line dictionaries, spelling
checkers, grammar and style checkers and style checkers.

Stage 3: Document production


This is the process of preparing the document for professional printing. It is supported by
desktop-publishing packages, artwork packages and type styling programs.

421
The final stage of document production is a skilled task that for documents with large
print runs, should be left to professional printers.

7.3.2 On-line documentation


The on-line documentation delivered with a system can range from simple ‘read me’
files that provide very limited information about the software through interactive help
systems to a complete web-based suite of system documentation including user
manuals, tutorials. Other systems have built-in help system that is delivered as part of
the application. Online documentation is part of user support systems that provide help
and support to system users.

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

Abstraction: The process of simplifying complex systems by modeling classes based on


essential properties and hiding unnecessary details.

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.

Algorithm: Algorithm is a step-by-step problem-solving process in which a solution is


arrived at in a finite amount of time

Algorithms: STL algorithms are predefined functions (like sort(), find(),


count()) that work with iterators to perform operations on containers.

Argument: An argument is a value that is passed to the function through function’s


parameter.

Array size: Total number of elements an array can hold.

Array: An array is a finite ordered collection of homogeneous data elements that provides
direct access (or random access) to any of its elements.

Assembler: Assembler is a program that translates program in low level language


(assembly language) into machine code

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

Base class: A class that is extended or inherited by another class.

Binary search: In binary search algorithm, to search a particular element, it is first


compared with the element at the middle position, and if found, the search is successful.
However, if the middle position value is greater than the target, the search will continue

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

Computer program: Computer program is a set of instructions that tells a computer


(hardware) to do a particular task.

Computer programming: Computer programming is a process of writing set of


instructions that tells a computer (hardware) to do a particular task

Constant: Constant is a location of a memory identified by a name whose content


cannot change.

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.

Dangling pointer: A pointer is said to be dangling if it is pointing to a memory location


that has been freed by a call to delete.

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

Debugging: Debugging is the process of finding and fixing errors, or bugs, in a


software program. It involves identifying, isolating, and correcting the problems that
prevent the program from running correctly.

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.

Dynamic memory allocation: The process of allocating memory at run-time is known as


dynamic memory allocation.

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.

Execution: Execution is running of a program in a computer.

Expression statement: An expression statement is a statement that result a value.

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

Flowchart: A flowchart is a graphical expression of an algorithm.

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 call: Function call is a statement that executes the function.

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.

Generic Programming: Generic programming is a programming style that focuses on


writing code that works with any data type, improving reusability and flexibility—commonly
implemented in C++ using templates.

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.

Index: Index is a value that shows/represents a position of an element in the array.

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.

Integration Testing: Integration testing is the phase in software testing where


individual units are combined and tested as a group. The goal is to expose faults in the
interaction between integrated units.

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.

Modular programming: Modular programming is broken up of a program into a set of


manageable functions, or modules.

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.

Object-oriented programming: Object oriented programming is a programming model


which is based upon the concept of objects.

Operand: An operand is a value or variable which gets operated by an operator.

Operator overloading: The ability to define custom behaviors for operators. For
example, you can define how the + operator works for objects of a class.

Operator: An operator is a symbol that operates on a value or variable to compute some


tasks.

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.

Placeholder Type: A placeholder type (like T, U, or typename T) is a symbolic name


used in templates to represent an unknown data type that will be specified when the
template is used.

Pointer arithmetic: Pointer arithmetic involves incrementing (add a value to) and
decrementing (subtract a value from) a pointer.

Pointer: A pointer is a variable whose value is the address of another variable.

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.

Procedural programming: Procedural programming is a programming model which is


derived from structured programming, based upon the concept of calling procedure or
functions.

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.

Profiler: A profiler collects statistics about a program’s execution allowing developers to


tune appropriate parts of the program to improve its overall performance.

Program control structures: Program control structures determine how execution of


the program should flow.

430
Program documentation: Program documentation is written text or illustration that
either explain how the software or application operate, or how to use it.

Program statement: A program statement is a small unit of code with a complete


programing thought.

Programmer: Programmer is a person who writes (develops) a computer program

Programming language: A programming language is a set of commands, instructions,


and other syntax use to create a computer program.

Pseudocode: A pseudocode is an algorithm written in something similar to programming


language but in a more understandable format.

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.

Searching: Searching is the process of locating target data.

Semantic: Semantic is the meaning of each statement in the program.

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.

Sort efficiency: It is an estimate of the number of comparisons and data movement


required to sort the data.

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.

Sorting: Sorting is a process of converting an unordered set of elements to an ordered


set of elements.

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.

Standard Template Library (STL) : The STL is a collection of ready-to-use, template-


based classes and functions in C++ that includes containers, iterators, and algorithms for
efficient data handling and manipulation.

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.

String: A string is array of characters

Structure: A structure is a programmer-defined data type that can hold many different
data values.

Subscript: Subscript is a number used to identify an element in an array, the subscript is


placed in brackets following the array name.

Syntax: Syntax are rules of writing statements in the program.

System documentation: System documentation includes all of the documents


describing the system itself from the requirements specification to the final acceptance
test plan.

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.

Template Instantiation: Template instantiation is the process where the compiler


generates actual code from a template by replacing placeholder types with specific data
types.

Template Specialization: Template specialization allows customizing the behavior of a


template for a specific data type, providing more control in certain situations.

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.

Variable: Is a location of a memory identified by a name whose content can change.

Virtual Functions: Functions declared in a base class and overridden by derived


classes. They allow dynamic binding and polymorphism.

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

Adesanya, M. (2017, October 12 ). A Gentler Introduction to Programming. Retrieved


from freecodecamp: [Link]
to-programming-1f57383a1b2c/
AltexSoft. (2018, June 16). Software Documentation Types and Best Practices.
Retrieved from [Link]: [Link]
types-and-best-practices-1726ca595c7f
B, R. (2020, August 15). Program Development Life Cycle. Retrieved from
btechsmartclass: [Link]
[Link]
Backman, K. (2012). Structured Programming with C++. London: Bookboon.
Bunch, G. (2020, July 21). A Guide to the Different Types of Coding Languages.
Retrieved from careerkarma: [Link]
languages/
Christodoulou, M., Szczygieł, E., Kłapa, Ł., & Kolarz, W. (2018). Algorithmic and
Programming. Krosno: P.T.E.A. Wszechnica Sp. z o.o.
Deitel, P. J., & Deitel, H. (2016). C++ How to Program, 10th Edition. Boston: Pearson
Education, Inc.
Deitel, P., & Deitel, H. (2022). C++20 for Programmers: An Objects-Natural Approach.
London: Pearson.

Dmitrovic, S. (2020). Modern C++ for absolute beginners: A friendly introduction to


C++programming language and C++11 to C++20 standards. Apress.

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

You might also like