Professional Documents
Culture Documents
INTRODUCTION TO PROGRAMMING
Computers are so widespread in our society because they have three advantages over us humans.
First, computers can store huge amounts of information. Second, they can recall that information
quickly and accurately. Third, computers can perform calculations with lightning speed and
perfect accuracy.
The advantages that computers have over us even extend to thinking sports like chess. In 1997,
the computer Deep Blue beat the world chess champion, Garry Kasparov, in a chess match. In
2003, Kasparov was out for revenge against another computer, Deep Junior, but only drew the
match. Kasparov, while perhaps the best chess player ever, is only human, and therefore no
match for the computer’s ability to calculate and remember prior games.
1
However, we have one very significant advantage over computers. We think on our own, while
computers don’t, at least not yet anyway. Indeed, computers fundamentally are far more brawn
than brain. A computer cannot do anything without step-by-step instructions from us telling it
what to do. These instructions are called a computer program, and of course are written by a
human, namely a computer programmer. Computer programs enable us to harness the
computer’s tremendous power.
2
The hardest part about programming is identifying all the little problems that make up the big
problem that you're trying to solve. Because computers are completely stupid, you need to tell
them how to do everything.
If you want to tell your friend how to prepare a meal say, nshima, you don’t have to tell them all
the details. For the computer however these may not be clear. You need to specify how much
Millie meal, how big should the pot be, how long the water boil, and many other specific and
precise details should.
You need to tell computers how to do everything, which can make giving them instructions as
aggravating and frustrating as telling children what to do. Unless you specify everything that you
want the computer to do and exactly how to do it, the computer on its own will not know how to
do what you want it to do.
A microprocessor, which is the heart of a computer, is very primitive but very fast. It takes
groups of bits and moves around their contents, adds pairs of groups of bits together, subtracts
one group of bits from another, compares a pair of groups, etc. Inside a microprocessor, at a very
low level, everything is simply a bunch of switches, also known as bits - things that are either on
or off!
Table 1.0 ASCII character set, just enough to give you a flavor of its organization.
ASCII in in in in
Character Binary Octal Decimal Hex
Space 00100000 040 32 20
( 00101000 050 40 28
) 00101001 051 41 29
* 00101010 052 42 2A
0 00110000 060 48 30
1 00110001 061 49 31
2 00110010 062 50 32
9 00111001 071 57 39
A 01000001 101 65 41
B 01000010 102 66 42
C 01000011 103 67 43
Z 01011010 132 90 5A
A 01100001 141 97 61
B 01100010 142 98 62
C 01100011 143 99 63
Z 01111010 172 122 7A
This might look a bit strange but the main point you have to pick up from here is that the computer does
not store data as we do using different characters, rather everything is stored as bit. You will learn more
about this fact in computer Architecture.
4
There is a difference between the language that a computer understands and the languages that we use as
humans. So then the question is in which language can we speak to the computer so that it can understand
us?
Problem analysis and program development: where you will learn how to design a
program before you implement it. We shall also cover the tools that are used in this.
Implementing a program design: this will include the actual program in c++. We shall use
c++ because it is best optimized for learning.
Structured programming: were you will learn advanced programming skills that will
prove useful in programming.
To begin let us talk about programming languages before were cover the other topics outlined
above.
UNIT SUMMARY
A program is a set of instructions used by the computer to carry out a task. The
instructions must be precise and specific.
Programming is the art of writing computer programs
Programming is problem solving
Computers do not understand the languages that used by humans. They use 0s and 1s to
represent data.
Programming is done using a programming language
5
EXERCISE
UNIT 2
COMPUTER PROGRAMMING LANGUAGES
6
Resources you will need: Internet
7
2.2 What Is A Programming Language
A programming language is a notation for specifying a sequence of operations to be carried out
by a computer. Programming languages are artificial languages created to tell the computer what
to do. They consist of vocabulary and a set of rules to write programs.
Tip: think of a programming language the same way you think of the different languages you
know e.g English, Bemba, French. Each of these languages can be used to make the same
instructions but not using the same grammar. That is the idea behind programming languages!!!
A programming language has a vocabulary and set of grammatical rules for instructing a
computer to perform specific tasks. The term programming language usually refers to high-level
languages, such as BASIC, C, C++, COBOL, FORTRAN, Ada, and Pascal. These are quite
advanced languages, at least above machine code, because they are able to use languages which
can readily be perceived by humans. Just as people speak many languages, you should
understand there are different kinds of programming languages.
8
idea of tvhe market the languages were intended for.
1. A place for storing data. Arrays are advanced storing data facility. Also known as data
structures.
2. Rules for writing programs in that programming language
3. Control statements – which are building blocks for logic implementation.
4. Most programming languages of today support Object Oriented Programming (OOP). So,
constructs to implement like features Class declaration, objects, inheritance,
polymorphism and constructors are included.
5. Every language has operators. Operators are used execute mathematical operations.
6. All languages include facility to write programs, functions and procedures. Incidentally,
this is the place where you write your programs. Functions return values after execution,
whereas procedures simply execute programs.
7. All programs include facility to write libraries. Libraries are themselves programs, which
can be used in other programs.
8. All languages support exception handling. This feature is helpful to identify errors and
generate appropriate messages.
9. All languages include built in functionalities, provided as classes and functions. These
classes help to write better programs.
10. All languages include a compiler and memory handling features. These are implemented
in different ways by the person(s) who developed the language.
9
2.5.1 Machine Languages: the First Generation
A machine language consists of the numeric codes for the operations that a particular computer
can execute directly. The codes are strings of 0s and 1s, or binary digits (“bits”), which are
frequently converted both from and to hexadecimal (base 16) for human viewing and
modification. Machine language instructions typically use some bits to represent operations, such
as addition, and some to represent operands, or perhaps the location of the next instruction.
Machine language is difficult to read and write, since it does not resemble conventional
mathematical notation or human language, and its codes vary from computer to computer.
Assembly language is one level above machine language. It uses short mnemonic codes for
instructions and allows the programmer to introduce names for blocks of memory that hold data.
One might thus write “add pay, total” instead of “0110101100101000” for an instruction that
adds two numbers. (Hemmendinger, 2015). Machine code programs are very efficient, but
obviously difficult to write.
Assembly languages use abbreviation or mnemonics such as ADD that are automatically
converted to the appropriate sequence of 1s and 0s
Assembly languages are much easier to use than machine language, but still more
difficult to use than higher level languages
These tend to be hardware dependent, but very efficient
This is a second level programming language. It is a variant of machine language in which
names and symbols take the place of the actual codes for machine operations , values and storage
locations , making individual instructions more readable
mov ax, WORD PTR Long1[0] ; AX = low word, long1
mov dx, WORD PTR Long1[2] ; DX = high word, long1
add ax, WORD PTR Long2[0] ; Add low word, long2
adc dx, WORD PTR Long2[2] ; Add high word, long2
ret ; Result returned as DX:AX
10
2.5.3 High-level Languages: Third Generation
These are considered portable languages because they are not tied specifically to certain
hardware like machine and assembly languages. This implies that you can write a program on
one machine, and transfer the same program on another machine and it will run successfully.
High level languages are not tied to a specific machine. These languages are also referred to as
procedural languages. This is because of the fact that they are designed to express the logic
procedures to solve general problems.
Examples of languages in this generation include Cobol, Basic, Fortran, and C++, Basic, Pascal,
C e.t.c. Depending on the language, the source code is translated into machine code using an
interpreter or a compiler. (you will soon learn about compilers and interpreters). Once compiled,
the program code can be stored as the object code, which is then saved to be run over and over
(without going through the compile process each time). Pascal, Cobol, and Fortran use
compilers.
An interpreter does a similar process, only the translated code is not saved – each time the
program is run, it is interpreted into machine code and run again. The Basic programming
language uses an interpreter.
Take note that each language can use either an interpreter or a compiler.
11
In this generation we find such languages as the following;
Query Languages
Query languages enable non-programmers to use certain easily understood
commands to search and generate reports from a database
Structured Query Language (SQL) is one of the most widely used query languages
Application Generators
An application generator (aka program coder) is a program that provides modules
of prewritten code.
Programmers can quickly create a program by referencing the appropriate modules
MS Access has a report generation application and a Report Wizard for quickly
creating reports
Because they are easier to use compared to 3rd generation languages, 4th generation languages are
called Very High Level Languages.
The following diagram can help you to have an overview of the programming languages
12
Machine language is the language that interacts directly with the hardware. This explains why it
is suppose to be machine specific. Assembly language is quite close to hardware and hence is
also machine specific.
By now you have a good understanding of programming languages. Let’s take a close look at
high level languages and what is involved in executing their programs in terms of compiling and
interpreting.
13
2.6.2 Interpreters
Interpreters, proceed through a program by translating and then executing single instructions or
small group of instructions. An Interpreter takes a program and its input at the same time. It
translates the program, implementing operations as it encounters them, and doing input/output as
necessary. One main advantage of an interpreter is that execution as well as syntax errors are
detected as each statement is encountered, thus debugging is easier in interpreted languages.
With an interpreter, the language comes as an environment, where you type in commands at a
prompt and the environment executes them for you. For more complicated programs, you can
type the commands into a file and get the interpreter to load the file and execute the commands
in it. If anything goes wrong, many interpreters will drop you into a debugger to help you track
down the problem.
The advantage of this is that you can see the results of your commands immediately, and
mistakes can be corrected readily. The biggest disadvantage comes when you want to share your
programs with someone. They must have the same interpreter, or you must have some way of
giving it to them, and they need to understand how to use it. Also users may not appreciate being
thrown into a debugger if they press the wrong key! From a performance point of view,
interpreters can use up a lot of memory, and generally do not generate code as efficiently as
compilers.
It can however be said that, interpreted languages are the best way to start if you have not done
any programming before. This kind of environment is typically found with languages like Lisp,
Smalltalk, Perl and Basic.
2.6.3 Compilers
Compilers translate the entire program into machine language before executing any of the
instructions. Compilers translate source code into machine oriented target code called object
code. After source code is compiled into object code , no futher references is made to the source
language.
First of all, you write your code in a file (or files) using an editor. You then run the compiler and
see if it accepts your program. If it did not compile, grit your teeth and go back to the editor; if it
did compile and gave you a program, you can run it either at a shell command prompt or in a
debugger to see if it works properly.
14
an IR as the compiler's internal representation of the program enables the compiler to be broken
up into multiple phases and components, thus benefiting from modularity.
An IR is any data structure that can represent the program without loss of information so that its
execution can be conducted accurately. It serves as the common interface among the compiler
components. Since its use is internal to a compiler, each compiler is free to define the form and
details of its IR, and its specification needs to be known only to the compiler writers. Its
existence can be transient during the compilation process, or it can be output and handled as text
or binary files.
15
Figure 2.2 Intermediate representation as an intermediate (Chow, 2013)
Using an IR enables a compiler to support multiple front ends that translate from different
programming languages and multiple back ends to generate code for different processor targets
(figure below). The execution platform can also be interpretive in the sense that its execution is
conducted by a software program or virtual machine. In such cases, the medium of execution can
be at a level higher than assembly code, while being lower or at the same level as the IR.
16
Figure 2.3 Main aim of intermediate representation (Chow, 2013)
Key
A compiler is a program that changes source code to object code
An interpreter translates source code one line at a time and executes the instruction
17
Libraries
If you had to create everything from scratch every time you wrote a program, it would be tedious
indeed. The same kind of functionality is often required in many programs—reading data from
the keyboard, for example, or displaying information on the screen. To address this,
programming languages tend to come supplied with considerable quantities of pre-written code
that provides standard facilities such as these, so you don’t have to write the code for them
yourself.
Standard code intended for use in any program is kept in a library. The library that comes with a
particular programming language is as important as the language itself, as the quality and scope
of the library can have a significant effect on how long it will take you to complete a given
programming task.
The object file produced by the compiler cannot be executed .If the source contains library
functions the code for these functions are not included in the object file. It is the job of the Linker
to integrate the code of the library functions with the object code into a single executable file.
Executable File
It is a file in a format that the computer can directly execute. Unlike source file, executable files
cannot be read by humans. To transform a source file into an executable file you need to pass it
through a compiler or assembler Example of Compiled Languages are C, C++. The translation of
a source program into object code is said to occur at translation time. Once translation is
complete the object code is run at a later time called run time. The object code created by the
compiler occupies more space than machine code .
18
2.7 Program Languages Semantics And Syntax
Each programming language has a unique set of keywords (words that it understands) and a
special ‘grammar’ for organizing program instructions. Syntax of a computer language is the set
of rules that defines the combinations of symbols that are considered to be a correctly structured
document or fragment in that language. This applies both to programming languages, where the
document represents source code, and markup languages, where the document represents data.
The syntax of a language defines its surface form. Text-based computer languages are based on
sequences of characters, while visual programming languages are based on the spatial layout and
connections between symbols (which may be textual or graphical). Documents that are
syntactically invalid are said to have a syntax error. This is synonymous to the languages we
speak. If someone wants to ask for water, what do you expect them to say? “may I please have
some water”. This is grammatically correct. What about this, “I please some may water? have”.
This is grammatically incorrect. This is similar to a syntax error in a programming language.
Syntax – the form – is contrasted with semantics – the meaning. In programming languages,
semantic processing generally comes after syntactic processing, but in some cases semantic
processing is necessary for complete syntactic analysis, and these are done together
or concurrently. In a compiler, the syntactic analysis comprises the frontend, while semantic
analysis comprises the backend (and middle end, if this phase is distinguished).
Implementing a programming language means bridging the gap from the programmer's high-
level thinking to the machine's zeros and ones. If this is done in an efficient and reliable way,
programmers can concentrate on the actual problems they have to solve, rather than on the
details of machines. But understanding the whole chain from languages to machines is still an
essential part of the training of any serious programmer. It will result in a more competent
programmer, who will moreover be able to develop new languages. A new language is often the
best way to solve a problem, and less difficult than it may sound.
19
an error on translation or execution. In some cases, such programs may exhibit undefined
behavior. Even when a program is well-defined within a language, it may still have a meaning
that is not intended by the person who wrote it.
2.9 Bytecode
Bytecode, also known as p-code (portable code), is a form of instruction set designed for
efficient execution by a software interpreter. Unlike human-readable source code, bytecodes are
compact numeric codes, constants, and references (normally numeric addresses) which encode
the result of parsing and semantic analysis of things like type, scope, and nesting depths of
program objects. They therefore allow much better performance than direct interpretation of
source code.
The name bytecode stems from instruction sets which have one-byte opcodes followed by
optional parameters. Intermediate representations such as bytecode may be output
by programming language implementations to ease interpretation, or it may be used to reduce
hardware and operating system dependence by allowing the same code to run on different
20
platforms. Bytecode may often be either directly executed on a virtual machine (i.e. interpreter),
or it may be further compiled into machine code for better performance.
Since bytecode instructions are processed by software, they may be arbitrarily complex, but are
nonetheless often akin to traditional hardware instructions; virtual stack machines are the most
common, but virtual register machines have also been built. Different parts may often be stored
in separate files, similar to object modules, but dynamically loaded during execution
Because of its performance advantage, today many language implementations execute a program
in two phases, first compiling the source code into bytecode, and then passing the bytecode to the
virtual machine. There are bytecode based virtual machines of this sort
for Java, Python, PHP, Tcl, and Forth (however, Forth is not ordinarily compiled via bytecodes
in this way, and its virtual machine is more generic instead). The implementation
of Perl and Ruby 1.8 instead work by walking an abstract syntax tree representation derived from
the source code.
21
ways, the JVM translates the programming code so that the two machines that may be on
different platforms are able to connect. (Beal, 1995)
A JVM language is any language with functionality that can be expressed in terms of a valid
class file which can be hosted by the Java Virtual Machine. A class file contains Java Virtual
Machine instructions (or bytecode) and a symbol table, as well as other support information.
EXERCISE
UNIT SUMMARY
22
Interpreters, proceed through a program by translating and then executing single
instructions or small group of instructions.
Syntax of a computer language is the set of rules that defines the combinations of
symbols that are considered to be a correctly structured document or fragment in that
language.
Semantics refers to the meaning of statements in a programming language.
There are five generations of programming languages i.e. 1st, 2nd…5th generations.
UNIT 3
The System Development is the interactive process which consists of the following stages. These
stages may vary slightly depending on which book you are reading or which model you are
following.
Sometimes software needs to be written to specific criteria rather than be purchased from a shop.
There are times that software must do specific things that just cannot be done by software that is
purchased off-the-shelf. When this occurs, software development is undertaken during the
23
development phases of the SDLC. A separate set of steps are engaged for the development of
software. These steps are:
Analysis
Design
Development (coding and debugging)
Testing
Documentation
Implementation and
Evaluation
Programs are logical sets of instructions that can be understood and executed by a computer.
They are used to direct the computer to perform the functions that transform data into
information. Programs are usually developed using a general-purpose information-processing
language comprising sets of symbols and codes that are used to construct a logical sequence of
instructions.
Some programming languages are designed to create programs for particular purposes but can be
used for other purposes as well. For example, COBOL is used for business applications, Fortran
for scientific and engineering purposes, Lisp for creating artificial intelligence programs, Java for
developing programs that run on a range of hardware platforms, dBASE for producing database
applications, Visual Basic for Applications (VBA) is used with Microsoft products such as
Access, and Excel to customise the way they process data.
If a decision is made in the design stage of the SDLC to use custom-built software, then a set of
program specifications is produced. They specify the data and the input-processing-output
components of the program to be developed. When the development stage is underway, program
specification are given to the programming team so they can start work. As the program is
developed, it progresses through the following series of stages.
24
but with more detail of course. Analysis in software development can involve interviews with the
system designer and with the future users of the programs so that a clearer understanding of the
requirements is communicated.
The next step is to define the purpose and method of operation of each module as an algorithm.
An algorithm is a description of a procedure or set of instructions required to perform a specific
task, and contains descriptions of the data to be used. Various design tools can be used to
represent the algorithm, such as flowcharts, Nassi-Schneidermann diagrams and structured
English (pseudocode). The algorithms for the modules must be clear for the programmer to work
from without the need to clarify them with the designer. The method used to represent the
structure and the algorithms depends on the type of programming language chosen. If an object-
orientated language is to be used the representation would be different from that used for a
procedure-based language.
The last part of the designs stage is checking the logic of the algorithms. This is checked using
specially designed test data and a process of stepping through the alogrithm called desk-
checking. It is much easier to correct errors in the design stage than when the program has been
written.
25
The development stage consists of two components: coding and debugging. These components
are done in an iterative manner, moving from debugging back to coding, and then debugging the
new code, and so on until all errors are found and removed.
Coding occurs when errors are removed from the code. Errors are generally of two types:
1. Syntax errors, which are often spelling mistakes.
2. Logic errors, which give wrong results.
The same test data that was used in the design stage desk-checking is used to check the logic as
the results are already known. Modern languages have extensive debugging tools built into an
integrated development environment (IDE) that allow tracking of the value of variables as the
program is run instruction by instruction. These tools greatly assist in the debugging process as
the results of each step are checked.
3.1.5 IMPLEMENTATION
The implementation stage invovles the installation of the program in the environemtn where it
will be tested against live data with trained users. This type of testing is often more thorough than
specially designed test data. The implementation may only involve a small number of the end-
users to begin with and then extend to all the staff and branches.
26
3.1.5 EVALUATION STAGE
The program is usually evaluated some time after it has been fully implemented within the
organisation. This is known as the evaluation stage. The program is evaluated against criteria that
are specified in the program specifications and feedback from the users.
After the software development implementation and evaluation stages, the completed software
then rejoins the System Development Life Cycle. The SDLC has its own implementation and
evaluation stages. The implementation and evaluation of the software needs to be integrated with
the implementation and evaluation of the full information system.
27
UNIT SUMMARY
creating a program or software is a life cycle which involves a number of stages
Problem analysis stage aim at understanding the problem at hand so as to know the input
which will be required, the processing need, and the subsequent output
The Design stage aim at trying creating a solution to the identified problem using
program design tools
Development, also referred to as coding is the act of implementing the designed solution
into a program using an appropriate programming language.
Implementation means the program is used as required by the user to evaluate it.
Evaluation stage is when you are checking if the program you have produced does
what it was meant to do and meets the problem identified during analysis.
28
UNIT 4
PROGRAM DESIGN AND ALGORITHMS
4.0 Introduction
Let’s now discuss three tools used to convert algorithms into computer programs: flowcharts,
pseudocode, and hierarchy charts. As you have seen above, you not just write a program from
without – it must be designed first. This is similar to what a tailor does. Before they can sew an
29
outfit, they first design it. In a similar manner a program before it is put in programming
language is called an algorithm. There are three tools that are used to design programs. But then
how can we define an algorithm?
Everything we do every day, is about algorithms. For instance, whenever you mail a letter, you
must decide how much postage to put on the envelope. One rule of thumb is to use one stamp for
every five sheets of paper or fraction thereof. Suppose a friend asks you to determine the number
of stamps to place on an envelope. The following algorithm will accomplish the task.
1. Request the number of sheets of paper; call it Sheets. (input)
2. Divide Sheets by 5. (processing)
3. Round the quotient up to the next highest whole number; call it Stamps. (processing)
4. Reply with the number Stamps. (output)
The preceding algorithm takes the number of sheets (Sheets) as input, processes the
data, and produces the number of stamps needed (Stamps) as output. We can test the algorithm
for a letter with 16 sheets of paper.
1. Request the number of sheets of paper; Sheets = 16.
2. Dividing 5 into 16 gives 3.2.
3. Rounding 3.2 up to 4 gives Stamps = 4.
4. Reply with the answer, 4 stamps.
Of the program design tools available, the three most popular are the following:
1. Flowcharts: Graphically depict the logical steps to carry out a task and show how the
steps relate to each other.
2. Pseudocode: Uses English-like phrases with some Visual Basic terms to outline the task.
3. Hierarchy charts: Show how the different parts of a program relate to each other
30
4.3 PSEUDOCODE
Pseudocode is an abbreviated version of actual computer code (hence, pseudocode). The
geometric symbols used in flowcharts are replaced by English-like statements that outline the
process. As a result, pseudocode looks more like computer code than does a flowchart.
Pseudocode allows the programmer to focus on the steps required to solve a problem rather than
on how to use the computer language. The programmer can describe the algorithm in Visual
Basic-like form without being restricted by the rules of Visual Basic. When the pseudocode is
completed, it can be easily translated into the Visual Basic language. The following is
pseudocode for the postage stamp problem:
Pseudocode Examples
An algorithm is a procedure for solving a problem in terms of the actions to be executed and the
order in which those actions are to be executed. An algorithm is merely the sequence of steps
taken to solve a problem. The steps are normally "sequence," "selection, " "iteration," and a case-
type statement.
In C, "sequence statements" are imperatives. The "selection" is the "if then else" statement, and
the iteration is satisfied by a number of statements, such as the "while," " do," and the "for,"
while the case-type statement is satisfied by the "switch" statement.
Pseudocode is an artificial and informal language that helps programmers develop algorithms.
Pseudocode is a "text-based" detail (algorithmic) design tool.
31
Example 1: this pseudocode for a program that prints the text “Failed” of the marks of the
student is less than 60 and “Passed” if the marks entered is 60 or above
Print "passed"
else
Print "failed"
You can see that the statements Print "passed" and Print "failed" are dependent on the condition.
Hence they have been indented, ie not in the same line as the statement above. In the above
examples check other the statements which have been indented and circle them!
Example 2: this algorithms allows the user to enter grade of the marks obtained for 10 students,
and then compute the average of the marks obtained.
Example 3: the following psedocode lets the user enter grades. If a number of grades have been
entered, the program calculates and prints the average. If no grades have been entered the
program displays that ‘no grade have been entered’.
32
while the user has not as yet entered the sentinel
else
Example 4. The pseudocode below allows the user to enter marks for ten (10) student. If the
number of students who have passed is eight (8) or above then raise the tuition fees and print the
number of those who have passed and the number of those who have failed.
else
33
print the number of passes
Below are additional examples of algorithms. On top is the scenario or question, then followed
by the solution.
Step 1: Start
Step 4: Add num1 and num2 and assign the result to sum.
sum←num1+num2
Step 6: Stop
Scenario: Write an algorithm to find the largest among three different numbers
entered by user.
Step 1: Start
Step 4: If a>b
If a>c
34
Display a is the largest number.
Else
Else
If b>c
Else
Step 5: Stop
Step 1: Start
flag←1
i←2
flag←0
Go to step 6
5.2 i←i+1
Step 6: If flag=0
35
Display n is not prime
else
Display n is prime
Step 7: Stop
Step 1: Start
5.1: temp←second_term
5.3: first_term←temp
Step 6: Stop
For looping and selection, The keywords that are to be used include Do While...EndDo; Do
Until...Enddo; Case...EndCase; If...Endif; Call ... with (parameters); Call; Return ....; Return;
When; Always use scope terminators for loops and iteration.
As verbs, use the words Generate, Compute, Process, etc. Words such as set, reset, increment,
compute, calculate, add, sum, multiply, ... print, display, input, output, edit, test , etc. with careful
indentation tend to foster desirable pseudocode.
36
Do not include data declarations in your pseudocode.
The main benefit of hierarchy charts is in the initial planning of a program. We break down the
major parts of a program so we can see what must be done in general. From this point, we can
then refine each module into more detailed plans using flowcharts or pseudocode. This process is
called the divide-and-conquer method. The postage stamp problem was solved by a series of
instructions to read data, perform calculations, and display results. Each step was in a sequence;
that is, we moved from one line to the next without skipping over any lines. This kind of
structure is called a sequence structure. Many problems, however, require a decision to
determine whether a series of instructions should be executed. If the answer to a question is
37
“Yes,” then one group of instructions is executed. If the answer is “No,” then another is
executed. This structure is called a decision structure. Figure 4.1 contains the pseudocode and
flowchart for a decision structure.
4.5 Flowchats
Flowcharts are written with program flow from the top of a page to the bottom. Each command
is placed in a box of the appropriate shape, and arrows are used to direct program flow. It must
however be noted that at times, flow may sometimes go up, as will be seen from the forth-
coming examples.
38
Table 4.1 above shows flowchart symbols adopted by the American National Standards Institute
(ANSI). The main advantage of using a flowchart to plan a task is that it provides a pictorial
representation of the task, which makes the logic easier to follow. We can clearly see every step
and how each step is connected to the next. The major disadvantage with flowcharts is that when
a program is very large, the flowcharts may continue for many pages, making them difficult to
follow and modify.
Pseudocode program designs are both text-based, the statements are written. Flow charts are a
graphical method of designing programs and once the rules are learned are very easy to draw.
In any flow chat you will come across, it will portray the following elements which are a part of
programming;
The major symbols are the decision (the diamond symbol – refer to the table 4.1) and the
sequence (or process – the rectangle shape) symbols. The START and STOP symbols are called
the terminals. The subprocess symbol is a variation on the sequence symbol. There are also
connectors drawn between the symbols and you will see these used in the examples below. There
is at least one other sequence symbol which is used to represent input/output processes but I
think it is unnecessary so I don't use it.
There are some important rules concerning the symbols and these rules apply also to other ways
of stating algorithms:
Processes have only one entry point and one exit point.
Decisions have only one entry point, one TRUE exit point and one FALSE exit point.
39
Repetition
The example above is good illustration of a repetition case. A typical scenario where you might
apply this is with regard to counting which day you must go to school. Assume that there is no
holiday in that particular week. You will go to school for as long as the day is not a weekend.
you will go to school on Monday, then check if the following day is a weekend. if not you will
go to school again and then check if the current day is a weekend. if not you will go to school
again the following day.
This is somehow a bad algorithm for such a scenario because it will make you go to school on a
Saturday.
40
Such a flow chat demonstrates a repetition structure called “do while” or “repeat until”. It
executes some process and checks the condition latter. A better flowchat for the school scenario
above would be the one shown below.
This loop is called the while loop. The while loop is basically the reverse of the repeat until loop,
the decision comes first, followed by the process. The while loop is usually written so that it
iterates while the condition is true, the repeat iterates until the condition becomes true. An
interesting question is: When should a repeat loop be used rather than a while loop? and vice-
41
versa. The while loop should be used when it is possible that the process or processes which are
in the scope of the decision (that is, in the loop) may not need to execute. For example assume
you have a designed an air-conditioner controller program and the program turns on the
compressor while the ambient temperature is above the desired temperature. A while loop is a
good choice here since the ambient temperature may be at the desired level before the
compressor part of the program is executed. If a repeat loop (do while) was used then the
compressor would be turned on but it wouldn't be necessary.
Selection
42
The IF ... THEN is used to implement selection in this case is shown here and is also known as
the NULL ELSE, meaning that there is no ELSE part. We have used lines with arrow-heads
(connectors) to indicate the flow of sequence. Although this is important in flow charts once you
have gained some skill in using them and if you draw them carefully you will find that
determining the sequence is straight forward. A typical rule is to use arrow-heads on connectors
where flow direction may not be obvious.
The IF ... THEN ... ELSE ... construct has a process at each branch of the decision symbol. The
only difference here is that each value of the decision (TRUE/FALSE) has a process associated
with it.
43
Take a look at the flowchat below. It basically counts the number of even numbers
44
Figure 4.6 Even/Odd number program flowchat
sum = 0
count = 1
REPEAT
IF count is even THEN sum = sum + count
count = count + 1
UNTIL count > 20
DISPLAY sum
You can see quite clearly from this example what the price of flow charting is. There is quite a
bit of drawing to do in addition to writing the legend in the symbols.
The pseudocode is quite simple by comparison. May be you are thinking, “why bother so much
with symbols, how to connect them, after all they are quite difficult?” The major reasons are that
the flow chart.
is easier to read
more closely follows a standard, this is not the case with pseudocode
probably lends itself more readily to computer-aided techniques of program design
Well-drawn flow charts are easy to read. What must you do to draw well-drawn flow charts?
Here are a few rules:
45
2. The flow of sequence is generally from the top of the page to the bottom of the page. This
can vary with loops which need to flow back to an entry point.
3. Use arrow-heads on connectors where flow direction may not be obvious.
4. There is only one flow chart per page
5. A page should have a page number and a title
6. A flow chart on one page should not break and jump to another page
7. A flow chart should have no more than around 15 symbols (not including START and
STOP)
Maybe you can try this now and test your understanding.
46
Figure 4.7: Solution to summation/average program
One process can be further broken into additional processes called subprocesses. Sometimes it is
useful to use subprocesses. The subprocess is useful because:
In flow charts subprocesses are also useful in dealing with the flow charting rule that a flow chart
should have no more than 15 or so symbols on a page.
A subprocess flow chart can contain other subprocesses, there is no limit to how deeply these
could be nested.
47
Take an example of the following situation: a college accepts students on the basis of the
following requirements;
first checks if the candidate has a credit in English
if so then check if the candidate has a a credit or better in Mathematics
if so then the check if the student has an average of a credit in sciences
if so then check if they have any other credit. If the candidate passes all the above
requirements, then they are accepted
Can you think of how this can be implemented in flowchat? Look at the solution as figure 4.8
shows.
TRUE
FALSE
TRUE
FALSE TRUE
48
FALSE
FALSE
Lets now review the things you have learnt in this unit.
UNIT SUMMARY
49
programs can be made from algorithms. An algorithm defines a set of finite steps taken to
solve a particular problem
program can be designed using tools such as hierarchy chats, flowchats and pseudocode
Hierarchy chats are used to show the components that make up a program. They are are
used as a tool for divide and conquer.
UNIT 5
50
Resources you will need: Internet, computer, Dev C++ (a software which allows
you to write c++ code and compile it). You can download Dev C++ on the
internet or any other c++ too like code blocks.
5.0 Introduction
After you have made your design as outlined above, you need to implement it. You have to
create the programming in a particular programming language. In our case we shall learn how
implement the particular program in c++. If you understand how to do this in C++, you can
easily learn how to do this in other languages. Take not of the of the following as we do read this
unit;
The best way to learn a programming language is by writing programs. To do this you will
require an editor tool that will help you to be able write C++ code. Download dev c++ or code
blocks on the internet and use them to write you programs. Exact details of how to use these
tools will be explained and demonstrated in class. It is advisable you try out any program that we
discuss so that you can gain a thorough understanding of what will be talked about.
Typically, the first program beginners write is a program called "Hello World", which simply
prints "Hello World" to your computer screen. Although it is very simple, it contains all the
fundamental components C++ programs have:
51
4 int main()
5{
6 cout << "Hello World!";
7}
The left panel above shows the C++ code for this program. The right panel shows the result
when the program is executed by a computer. The grey numbers to the left of the panels are line
numbers to make discussing programs and researching errors easier. They are not part of the
program.
Lines beginning with a hash sign (#) are directives read and interpreted by what is known as
the preprocessor. They are special lines interpreted before the compilation of the program itself
begins. In this case, the directive#include <iostream>, instructs the preprocessor to include a
section of standard C++ code, known as header iostream, that allows to perform standard input
and output operations, such as writing the output of this program (Hello World) to the screen.
Blank lines have no effect on a program. They simply improve readability of the code.
This line initiates the declaration of a function. Essentially, a function is a group of code
statements which are given a name: in this case, this gives the name "main" to the group of code
statements that follow. Functions will be discussed in detail in a later chapter, but essentially,
their definition is introduced with a succession of a type (int), a name (main) and a pair of
parentheses (()), optionally including parameters.
The function named main is a special function in all C++ programs; it is the function called when
the program is run. The execution of all C++ programs begins with the main function, regardless
of where the function is actually located within the code.
52
The open brace ({) at line 5 indicates the beginning of main's function definition, and the closing
brace (}) at line 7, indicates its end. Everything between these braces is the function's body that
defines what happens when main is called. All functions use braces to indicate the beginning and
end of their definitions.
This line is a C++ statement. A statement is an expression that can actually produce some effect.
It is the meat of a program, specifying its actual behavior. Statements are executed in the same
order that they appear within a function's body.
This statement has two parts: cout, (read as ‘C OUT’) basically means ‘print this’ on the
computer screen. Second, the insertion operator (<<), which indicates what is to be printed.
Finally, a sentence within quotes ("Hello world!"), is the content inserted into the standard
output. (Kent, 2004)
Notice that the statement ends with a semicolon (;). This character marks the end of the
statement, just as the period ends a sentence in English. All C++ statements must end with a
semicolon character. One of the most common syntax errors in C++ is forgetting to end a
statement with a semicolon.
The program above indicates to you the basic structure of a C++ program. take note that all the
code that you want to write should come between the { and } following the int main()
5.1 Comments
As noted above, comments do not affect the operation of the program; however, they provide an
important tool to document directly within the source code what the program does and how it
operates.
1 // line comment
2 /* block comment */
The first of them, known as line comment, discards everything from where the pair of slash signs
(//) are found up to the end of that same line. The second one, known as block comment, discards
everything between the /* characters and the first appearance of the */ characters, with the
possibility of including multiple lines.
53
Let's add comments to our second program:
If comments are included within the source code of a program without using the comment
characters combinations //,/* or */, the compiler takes them as if they were C++ expressions,
most likely causing the compilation to fail with one, or several, error messages.
While doing programming in any 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.
You may like to store information of various data types like character, wide character, integer,
floating point, double floating point, boolean etc. Based on the data type of a variable, the
operating system allocates memory and decides what can be stored in the reserved memory. A
data type basically defines the nature (kind) of values stored in a particular location
C++ offer the programmer a rich assortment of built-in as well as user defined data types.
Following table lists down seven basic C++ data types:
54
Stores a single character on the -127 to 127 or 0
Character Char keyboard e.g “K”, “L”, “t”, ESC, to 255
ENTER
Several of the basic types can be modified using one or more of these type modifiers:
signed
unsigned
short
long
Table 5.1 shows the variable type, how much memory it takes to store the value in memory, and
what is maximum and minimum vaue which can be stored in such type of variables. (Stroustrup,
Variables and Data types, 1997)
The sizes of variables might be different from those shown in the above table, depending on the
compiler and the computer you are using. (Stroustrup, 1997)
55
5.3.2 Variable Definition in C++
A variable definition means to tell the compiler where and how much to create the storage for the
variable. A variable definition specifies a data type, and contains a list of one or more variables
of that type as follows:
type variable_list;
Here, type must be a valid C++ data type including char, w_char, int, float, double, bool or any
user-defined object, etc., and variable_list may consist of one or more identifier names separated
by commas. Some valid declarations are shown here:
int i, j, k;
char c, ch;
float f, salary;
double d;
The line int i, j, k; both declares and defines the variables i, j and k; which instructs the compiler
to create variables named i, j and k of type int.
When naming variables the following rules apply
1. a variable name cannot start with a number e.g ‘2Age’ is wrong. They can however have
a number in between e.g ‘Age2’ is a valid variable name.
2. Spaces are not allowed in variable names. Eg ‘Pupil Name’ is not valid. Such a variable
can be written with underscores as ‘Pupil_Name’ or ‘PupiName’
3. Variables should be named intelligently ie the name should be a reflection of the nature
of the values it is stroring. For example a variable storing the age of a puil is better off
named as ‘Pupil_Age’ instead of ‘A’ or ‘PA’. This is not really a rule of syntax but a
good programming practice and it contributes to the readability of a program.
A variable declaration provides assurance to the compiler that there is one variable existing with
the given type and name so that compiler proceed for further compilation without needing
complete detail about the variable. A variable declaration has its meaning at the time of
compilation only, compiler needs actual variable declaration at the time of linking of the
program.
Variables can be initialized (assigned an initial value) in their declaration. The initializer consists
of an equal sign followed by a constant expression as follows:
after the variables are declared, it can later on be assigned a value. The equal sign (=) is used to
assign a value to a variable as the following example can show
56
int d = 3, f = 5; // definition and initializing d and f.
char x = 'x'; // the variable x has the value 'x'.
#include <iostream>
using namespace std;
int main ()
{
// Variable definition:
int a, b;
int c;
float f;
// actual initialization
a = 10; // assign the value 10 to variable a
b = 20; // assign the value 20 to variable a
c = a + b; //add the value of a and and store the value in c
f = 70.0/3.0;
cout << f << endl ;
return 0;
}
(Kent, 2004)
When the above code is compiled and executed, it produces the following result:
30
23.3333
The statement cout << c << endl ; displays the value that is stores in the variable c and moves
the cursor into the next line because of the ‘endl’;
Take note that variable do not assume the same value throughout the program. Once assigned a
value, does not mean the variable will assume the same value all the time for example if we have
the statement;
57
This will not result into an error but will just overwrite the value written in a with the new value,
in this case 15.
An operator is a symbol that represents a specific action. We have discussed and used operators
in prior chapters, including the assignment operator, =. C++ also supports operators for
arithmetic, specifically addition, subtraction, multiplication, and division. Operators used for
arithmetic are called, naturally enough, arithmetic operators. Table 5.2 summarizes them.
The % operator, also called the modulus operator, may look unfamiliar. It returns the remainder
in division.
It is not usually the case that we need to assign values to variables in a program. Normally,
values for values are entered by the user. All we do is declare the variable and create a provision
for the user to enter the values.
Key: getting input from the user is done using the “cin” reserved word, which is read as ‘c in’.
the basic syntax is as follows
cin>>VariableName;
58
#include <iostream>
using namespace std;
int main(void)
{
int num;
cout << "Enter a whole number: ";
cin >> num; // captures the number entered by user into the variable num
cout << "The number is even" << endl;
return 0;
}
The if statement is used to execute code only when the value of a relational expression is true.
The syntax of an if statement is;
if (Boolean value)
statement;
Both lines together are called an if statement. The first line consists of the if keyword followed
by an expression, such as a relational expression, that evaluates to a Boolean value, true or false.
The relational (or other Boolean) expression must be in parentheses, and should not be
terminated with a semicolon.
The next line is called a conditional statement. Remember that a statement is an instruction to the
computer, directing it to perform a specific action. The statement is conditional because it
executes only if the value of the relational expression is true. If the value of the relational
expression is false, then the conditional statement is not executed—meaning, it’s essentially
skipped.
The following program, which tests if a whole number entered by the user is even, illustrates the
use of an if statement.
#include <iostream>
using namespace std;
int main(void)
{
int num;
cout << "Enter a whole number: ";
cin >> num;
if ( num % 2 == 0 )
cout << "The number is even" << endl;
return 0;
59
}
If the user enters an even number, then the program outputs that the number is even.
However, if the user enters an odd number, then there is no output that the number is even.
One problem with the program that tests whether a number is even is that there is no output if the
number is odd. While there is a conditional statement if the relational expression is true, there is
no corresponding conditional statement (cout << “The number is odd”) if the relational
expression is false.
The solution is to add an else part to the if statement. The result is an if / else statement. The
syntax of an if / else statement is
if (relational expression)
conditional statement;
else
conditional statement;
Accordingly, the program may be modified to add an else part to the if statement:
#include <iostream>
using namespace std;
int main(void)
{
int num;
cout << "Enter a whole number: ";
cin >> num;
if ( num % 2 == 0 )
cout << "The number is even" << endl;
else
cout << "The number is odd" << endl;
return 0;
}
Run this code. If the inputted number is even, then the output once again is “The number is
even.” However, if the number is now odd, instead of no output, the output is “The number is
odd.”
60
Enter a whole number: 17
The number is odd
Read through the following program and interpret it. Write down the output of this program i,e
write what the program will be priting on the screen wherever there is a cout.
#include <iostream>
using namespace std;
int main(void)
{
int age;
char choice;
bool citizen;
cout << "Enter your age: ";
cin >> age;
cout << "Are you a citizen (Y/N): ";
cin >> choice;
if (choice == 'Y')
citizen = true;
else
citizen = false;
if (age >= 18)
if(citizen == true)
cout << "You are eligible to vote";
else
cout << "You are not eligible to vote";
else
cout << "You are not eligible to vote";
return 0;
Check the solution from the following source: (Kent, Nested if Statements, 2004)
UNIT SUMMARY
61
Data type is a specification of the kind of variables stored in a variable
cout is used to display values and text in a program while cin is used for getting input
from the user.
Common data tyes in programming languages include Boolean, integers, floating point
number, characters, strings e.t.c
UNIT 6
62
STRUCTURED PROGRAMMING
6.0 Introduction
Structured programming is one way of programming aimed at improving the clarity, quality, and
development time of a computer program by making extensive use of subroutines, block
structures and for and while loops—in contrast to using simple tests and jumps such as the goto
statement which could lead to "spaghetti code" which is both difficult to follow and to maintain.
It has also been defined as a technique for organizing and coding computer programs in which a
hierarchy of modules is used, each having a single entry and a single exit point, and in which
control is passed downward through the structure without unconditional branches to higher levels
of the structure.
Three types of control flow are used: sequential, test (commonly known as selection), and
iteration.
At a low level, structured programs are often composed of simple, hierarchical program flow
structures. These are sequence, selection, and repetition:
63
"Sequence" refers to an ordered execution of statements.
In "selection" one of a number of statements is executed depending on the state of the
program. This is usually expressed with keywords such as if..then..else..endif, switch, or
case. In some languages keywords cannot be written verbatim, but must be stropped.
In "repetition" a statement is executed until the program reaches a certain state, or
operations have been applied to every element of a collection. This is usually expressed
with keywords such as while, repeat, for or do..until. Often it is recommended that each
loop should only have one entry point (and in the original structural programming, also
only one exit point, and a few languages enforce this).
Remember that this has been covered earlier on when we were looking at algorithms. The same
principles apply here.
The box diagrams represent the sequence of statements to executed while the diagram right next
to it represents the equivalent flowchats. (Wikipedia, 2006)
Many languages do support structured programming, of course with variations across several
languages. There are however similarities in structures among all programming languages. You
must recall from our lesson about algorithms that implementing a programs involves use of
conditions, ie a statements that can evaluate to true or false depending values involved. In many
languages, these are called Conditional statements, conditional expressions and conditional
constructs. These are features of a programming language which perform different computations
or actions depending on whether a programmer-specified boolean condition evaluates to true or
false. Apart from the case of branch predication, this is always achieved by selectively altering
the control flow based on some condition. This implies that the as the program is running, it
comes across a condition, then decides to run over (to execute) a block of statements depending
on whether the condition is true of false. Lets now examine common structures used to
implement structured programming.
64
6.2 Selection Structures
The if–then construct (sometimes called if–then–else) is common across many programming
languages. Although the syntax varies quite a bit from language to language, the basic structure
(in pseudocode form) looks like this:
When an interpreter finds an If, it expects a boolean condition – for example, x > 0, which means
"the variable x contains a number that is greater than zero" – and evaluates that condition. If the
condition is true, the statements following the then are executed. Otherwise, the execution
continues in the following branch – either in the else block (which is usually optional), or if there
is no else branch, then after the end If.
In this case its either statements 1 to 3 will be executed or statements 4 to 6 if the condition is
true of false respectively.
if condition then
--statements
Else
if condition then
-- more statements
Else
if condition then
- more statements;
...
End if
End if
End if
65
This creates a multiway selection structure where there is a chain of conditions that depend on
other condition. The key still remains the same: a block of statements will be executed or others
will depending on the conditions.
If all terms in the sequence of conditionals are testing the value of a single expression (e.g., if x
== 0 ... else if x == 1 ... else if x == 2), then an alternative is the switch statement.
You must, at least by now, know that the if statements just depends on a condition being true or
false. What if we have a situation where we say if this variable is say 1, they execute statements
1, if it is 2 they execute statement 2, if it is 3 then execute statement 3,… how can we implement
this? The other case of selection is the use of the switch statement. Look at the examples below.
In this example the Value can have different options. It is like multiple choice. Depending on the
value of Value, the program decides to execute different blocks of statements.
switch(Value)
{
case value1:
statement(s);
break;
case value2:
statement(s);
break;
case value3:
statement(s);
break;
default:
statement(s);
}
(Gookin, 2010)
When we want to implement multiple choice, we use the switch statements instead of the if-else
structure. Remember that it is also used to implement the selection structure.
66
6.3 Repetition Structures
This allows us to run a set of statements more than once. This is implemented using loops. Loops
are basically repetition structures in programming languages. We will examine some of the
common loops used in a number programming languages. These are while, do while, and repeat.
In most computer programming languages, a while loop is a control flow statement that allows
code to be executed repeatedly based on a given boolean condition. The while loop can be
thought of as a repeating if statement.
The while construct consists of a block of code and a condition. The condition is evaluated, and
if the condition is true, the code within the block is executed. This repeats until the condition
becomes false. Because while loop checks the condition before the block is executed, the control
structure is often also known as a pre-test loop. Compare with the do while loop, which tests the
condition after the loop has executed.
67
For example, in the C programming language (as well as Java, C# and C++, which use the same
syntax in this case), the code fragment
int x = 0;
while (x < 5)
{
cout<<x;
x = x+ 1;
}
The statements cout<<x; and x = x+ 1; are being repeated depeding on the condition specified
above as while (x < 5). This loop tests for the condition before it can execute the statements.
A do while loop is a control flow statement that allows code to be executed once based on a
given Boolean condition. Note though that unlike most languages, Fortran's do loop is actually
the same as the for loop. (Wikipedia, 2006)
The do while construct consists of a process symbol and a condition. First, the code within the
block is executed, and then the condition is evaluated. If the condition is true the code within the
block is executed again. This repeats until the condition becomes false. Because do while loops
check the condition after the block is executed, the control structure is often also known as a
post-test loop. Contrast with the while loop, which tests the condition before the code within the
block is executed.The do-while loop is an exit-condition loop. This means that the code must
68
always be executed first and then the expression or test condition is evaluated. If it is true, the
code executes the body of the loop again. This process is repeated as long as the expression
evaluates to true. If the expression is false, the loop terminates and control transfers to the
statement following the do-while loop.
It is possible, and in some cases desirable, for the condition to always evaluate to true, creating
an infinite loop. When such a loop is created intentionally, there is usually another control
structure (such as a break statement) that allows termination of the loop.
Some languages may use a different naming convention for this type of loop. For example, the
Pascal language has a "repeat until" loop, which continues to run until the control expression is
true (and then terminates) — whereas a "while" loop runs while the control expression is true
(and terminates once the expression becomes false).
Structured application programs require more discipline at the design and logical structuring
stage but they can be coded more quickly. The time required to reach the testing stage is roughly
the same, but the benefits of SPs are significant from this point and onward.
Using the SPs requires a more disciplined approach to programming and, therefore, provides the
following advantages:
69
EXERCISE: ANSWER THE FOLLOWING QUESTIONS
UNIT SUMMARY
UNIT 7
70
MODULAR PROGRAMMING
7.0 Introduction
A module is a separate software component. It can often be used in a variety of applications and
functions with other components of the system. Similar functions are grouped in the same unit of
programming code and separate functions are developed as separate units of code so that the
code can be reused by other applications. (Janssen, 2010)
Object-oriented programming (OOP) is compatible with the modular programming concept to a
large extent. Modular programming enables multiple programmers to divide up the work and
debug pieces of the program independently.
Modular programming is simply subdividing your program into separate subprograms such as
functions and subroutines. Use these. For example, if your program needs initial and boundary
conditions, use subroutines to set them. Then if someone else wants to compute a different
solution using your program, only these subroutines need to be changed. This is a lot easier than
having to read through a program line by line, trying to figure out what each line is supposed to
do and whether it needs to be changed. And in ten years from now, you yourself will probably no
longer remember how the program worked.
71
6.1 Why Use Modular Programming?
1. Subprograms make your actual program shorter, hence easier to read and understand.
Further, the arguments show exactly what information a subprogram is using. That makes
it easier to figure out whether it needs to be changed when you are modifying your
program. Forgetting to change all occurrences of a variable is a very common source of
errors.
2. Subprograms make it simpler to figure out how the program operates. If the boundary
conditions are implemented using a subroutine, your program can be searched for this
subroutine to find all places where the boundary conditions are used. This might include
some unexpected places, such as in the output, or in performing a numerical check on the
overall accuracy of the program.
3. Subprograms reduce the likely hood of bugs. Because subprograms can use local
variables, there is less change that the code in the subroutine interferes with that of the
program itself, or with that in other subprograms. The smaller size of the individual
modules also makes it easier to understand the global effects of changing a variable.
4. A single procedure can be developed for reuse, eliminating the need to retype the code
many times.
5. Programs can be designed more easily because a small team deals with only a small part
of the entire code.
6. Modular programming allows many programmers to collaborate on the same application.
7. The same code can be used in many applications – which is know as code re-use
8. The scoping of variables can easily be controlled.
Modules in modular programming enforce logical boundaries between components and improve
maintainability. They are incorporated through interfaces. They are designed in such a way as to
minimize dependencies between different modules. Teams can develop modules separately and
do not require knowledge of all modules in the system. (Janssen, 2010)
72
6.2 Types of Subprograms
I. Procedure and
II. Functions (return type, name, arguments code block),
A procedure prescribes a group of instruction for parameterized computation, and defines a new
statement. A procedure produces results by altering either the parameters or the non-local
variable but does not have return value. It prescribes a group of instruction for parameterized
computation, and defines a new statement. A procedure produces results by altering either the
parameters or the non-local variable since it does not have return value.
A function models after a mathematic relation between a set of parameters and a return value,
therefore a function defines a new operator. A pure function produces result not by side effects,
but by the return value. Otherwise a function could work just like a procedure by side effects.
The major difference between the two is that a procedure does not return a value while a function
does. A function models after a mathematic relation between a set of parameters and a return
value, therefore a function defines a new operator. A pure function produces result not by side
effects, but by the return value. Otherwise a function could work just like a procedure by side
effects.
6.3 Implementing Subprograms
Subprogram is a form of process abstraction. Relative instructions for accomplishing a task are
grouped together as a logical unit. The concept not only saves space but also code development
efforts. A subprogram is basically a unit of the whole programming that performs a specific task.
It has a name, which can be used to call it form the main program or other subprograms. Take a
look at the program segment below.
void printmessage ()
{
cout << "I'm a function!";
}
int main ()
{
printmessage ();
return 0;
73
}
If you have understand how to write a program, in C++ you must understand the main () part of
the program. This is the main program, it being the first part of the program that is executed
when the program starts running. This can be also be referred to as a subprogram. The other
subprogram is the one with the label ‘print message’
int main ()
{
Int x, y;
74
x = 5;
y = 9;
cout<<AddNumbers(x,y);
return 0;
}
Program listing 7.1: subprogram example
This example will help you to understand the concepts that will be discussed below. It highlights
a good example of a subprogram. AddNumbers is a subprogram performing a specific task of
adding two numbers and return the sum.
6.3.3 Parameters
A subprogram can access the data outside by either parameter or non-local variables. The latter is
not as convenient as the former. Local variables are the variables declared inside a subprogram.
For example the variables a and b in the AddNumbers subprogram, the variable sum is a local
variable that is known only within that subprogram. The variables x and y in the main() are local,
ie only recognized inside the main().
In some cases a subprogram can be passed into another subprogram as a parameter for
programming flexibility. Given the program above
the variables a and b are parameters. These are referred to as formal parameters. They are meant
to receive two integers, which the function calls a and b.
Keyword parameters map the actual parameters to formal ones by the names, and positional
parameters does it by the order actual parameters appear. Using keyword parameters requires the
knowledge of parameter names, but is more readable and reliable. Parameters may have default
values. They must appear last in the parameter list so that the compiler can determine the
mapping.
What we did in this case was to call to function addition passing the values of x and y, i.e. 5 and
75
3 respectively, but not the variables x and y themselves.
This way, when the function addition is called, the value of its local variables a and b become 5
and 3 respectively, but any modification to either a or b within the function addition will not
have any effect in the values of x and y outside it, because variables x and y were not themselves
passed to the function, but only copies of their values at the moment the function was called.
But there might be some cases where you need to manipulate from inside a function the value of
an external variable. For that purpose we can use arguments passed by reference, as in the
function duplicate of the following example:
The first thing that should call your attention is that in the declaration of duplicate the type of
each parameter was followed by an ampersand sign (&). This ampersand is what specifies that
their corresponding arguments are to be passed by reference instead of by value.
76
When a variable is passed by reference we are not passing a copy of its value, but we are
somehow passing the variable itself to the function and any modification that we do to the local
variables will have an effect in their counterpart variables passed as arguments in the call to the
function.
To explain it in another way, we associate a, b and c with the arguments passed on the function
call (x, y and z) and any change that we do on a within the function will affect the value of x
outside it. Any change that we do on b will affect y, and the same with c and z.
That is why our program's output, that shows the values stored in x, y and z after the call to
duplicate, shows the values of all the three variables of main doubled.
i.e., without the ampersand signs (&), we would have not passed the variables by reference, but a
copy of their values instead, and therefore, the output on screen of our program would have been
the values of x, y and z without having been modified.
Passing by reference is also an effective way to allow a function to return more than one value.
For example, here is a function that returns the previous and next numbers of the first parameter
passed. (Kent, 2004)
77
8 next = x+1;
9}
10
11 int main ()
12 {
13 int x=100, y, z;
14 prevnext (x, y, z);
15 cout << "Previous=" << y << ", Next=" <<
16 z;
17 return 0;
}
UNIT SUMMARY
We have covered a number of things in this unit. The most important things are the following;
78
f
UNIT 8
79
DATA STRUCTURES- STORAGE AND ORGANISATION OF DATA
A data structure is a particular way of storing and organizing data in a computer so that it can be
used efficiently. It can also be defined as a collection of data items, in addition a number of
operations are provided by the software to manipulate the data structure.
Different kinds of data structures are suited to different kinds of applications, and some are
highly specialized to specific tasks. For example, B-trees are particularly well-suited for
implementation of databases, while compiler implementations usually use hash tables to look up
identifiers.
Data structures provide a means to manage large amounts of data efficiently, such as large
databases and internet indexing services. Usually, efficient data structures are a key to designing
efficient algorithms. Some formal design methods and programming languages emphasize data
structures, rather than algorithms, as the key organizing factor in software design. Storing and
retrieving can be carried out on data stored in both main memory and in secondary memory.
80
A primitive data type is either of the following:
1. basic type is a data type provided by a programming language as a basic building block.
Most languages allow more complicated composite types to be recursively constructed
starting from basic types.
2. built-in type is a data type for which the programming language provides built-in support.
In most programming languages, all basic data types are built-in. In addition, many languages
also provide a set of composite data types. Opinions vary as to whether a built-in type that is not
basic should be considered "primitive".
Depending on the language and its implementation, primitive data types may or may not have a
one-to-one correspondence with objects in the computer's memory. However, one usually
expects operations on basic primitive data types to be the fastest language constructs there are.
Integer addition, for example, can be performed as a single machine instruction, and some
processors offer specific instructions to process sequences of characters with a single instruction.
Most languages do not allow the behavior or capabilities of primitive (either built-in or basic)
data types to be modified by programs. Exceptions include Smalltalk, which permits all data
types to be extended within a program, adding to the operations that can be performed on them
or even redefining the built-in operations.
A composite data type is any data type which can be constructed in a program using its
programming language's primitive data types and other composite types. The act of constructing
a composite type is known as composition.
Static data structures are very good for storing a well-defined number of data items.
81
For example a programmer might be coding an 'Undo' function where the last 10 user actions are
kept in case they want to undo their actions. In this case the maximum allowed is 10 steps and so
he decides to form a 10 item data structure.
There are many situations where the number of items to be stored is not known before hand.
In this case the programmer will consider using a dynamic data structure. This means the data
structure is allowed to grow and shrink as the demand for storage arises. The programmer should
also set a maximum size to help avoid memory collisions.
For example a programmer coding a print spooler will have to maintain a data structure to store
print jobs, but he cannot know before hand how many jobs there will be. The table 8.1 below
compared the two approaches.
82
Data structures are generally based on the ability of a computer to fetch and store data at any
place in its memory, specified by an address—a bit string that can be itself stored in memory and
manipulated by the program. Thus the record and array (examples of data structures) data
structures are based on computing the addresses of data items with arithmetic operations; while
the linked data structures are based on storing addresses of data items within the structure itself.
Many data structures use both principles.
An abstract data type (ADT) is a mathematical model for a certain class of data structures that
have similar behavior; or for certain data types of one or more programming languages that have
similar semantics. An abstract data type is defined indirectly, only by the operations that may be
performed on it and by mathematical constraints on the effects (and possibly cost) of those
operations.
For example, an abstract stack could be defined by three operations: push, that inserts some data
item onto the structure, pop, that extracts an item from it (with the constraint that each pop
always returns the most recently pushed item that has not been popped yet), and peek, that allows
data on top of the structure to be examined without removal. When analyzing the efficiency of
algorithms that use stacks, one may also specify that all operations take the same time no matter
how many items have been pushed into the stack, and that the stack uses a constant amount of
storage for each element.
Abstract data types are purely theoretical entities, used (among other things) to simplify the
description of abstract algorithms, to classify and evaluate data structures, and to formally
describe the type systems of programming languages. However, an ADT may be implemented
by specific data types or data structures, in many ways and in many programming languages; or
described in a formal specification language. ADTs are often implemented as modules: the
module's interface declares procedures that correspond to the ADT operations, sometimes with
comments that describe the constraints. This information hiding strategy allows the
implementation of the module to be changed without disturbing the client programs. The
following are some examples of abstract data structures.
8.5.1 Queues
83
A queue is a particular kind of abstract data type or collection in which the entities in the
collection are kept in order and the principal (or only) operations on the collection are the
addition of entities to the rear terminal position, known as enqueue, and removal of entities from
the front terminal position, known as dequeue. This makes the queue a First-In-First-Out (FIFO)
data structure. In a FIFO data structure, the first element added to the queue will be the first one
to be removed. This is equivalent to the requirement that once a new element is added, all
elements that were added before have to be removed before the new element can be removed.
Often a peek or front operation is also implemented, returning the value of the front element
without dequeuing it. A queue is an example of a linear data structure, or more abstractly a
sequential collection.
Figure 8.1 Representation of a Queue with FIFO (First In First Out) property
Queues provide services in computer science, transport, and operations research where various
entities such as data, objects, persons, or events are stored and held to be processed later. In these
contexts, the queue performs the function of a buffer.
Queues are common in computer programs, where they are implemented as data structures
coupled with access routines, as an abstract data structure or in object-oriented languages as
classes. Common implementations are circular buffers and linked lists.
APPLICATION OF QUEUES
Queues are used for any situation where you want to efficiently maintain a First-in-first out order
on some entities. These situations arise literally in every type of software development.
Imagine you have a web-site which serves files to thousands of users. You cannot service all
requests, you can only handle say 100 at once. A fair policy would be first-come-first serve:
serve 100 at a time in order of arrival. A Queue would definitely be the most appropriate data
structure.
84
Similarly in a multitasking operating system, the CPU cannot run all jobs at once, so jobs must
be batched up and then scheduled according to some policy. Again, a queue might be a suitable
option in this case. The same applies for a printer which creates schedule of printing jobs on first
come first serve basis
A stack is a particular kind of abstract data type or collection in which the principal (or only)
operations on the collection are the addition of an entity to the collection, known as push and
removal of an entity, known as pop. The relation between the push and pop operations is such
that the stack is a Last-In-First-Out (LIFO) data structure. In a LIFO data structure, the last
element added to the structure must be the first one to be removed. This is equivalent to the
requirement that, considered as a linear data structure, or more abstractly a sequential collection,
the push and pop operations occur only at one end of the structure, referred to as the top of the
stack. Often a peek or top operation is also implemented, returning the value of the top element
without removing it.
A stack may be implemented to have a bounded capacity. If the stack is full and does not contain
enough space to accept an entity to be pushed, the stack is then considered to be in an overflow
state. The pop operation removes an item from the top of the stack. A pop either reveals
previously concealed items or results in an empty stack, but, if the stack is empty, it goes into
underflow state, which means no items are present in stack to be removed.
A stack is a restricted data structure, because only a small number of operations are performed
on it. The nature of the pop and push operations also means that stack elements have a natural
order. Elements are removed from the stack in the reverse order to the order of their addition.
Therefore, the lower elements are those that have been on the stack the longest.
85
Applications Of Stacks Data Structures
Stacks have numerous applications. We see stacks in everyday life, from the books in our library,
to the sheaf of papers that we keep in our printer tray. All of them follow the Last In First Out
(LIFO) logic, that is when we add a book to a pile of books, we add it to the top of the pile,
whereas when we remove a book from the pile, we generally remove it from the top of the pile.
To solve this problem, we use a stack. We make use of the LIFO property of the stack. Initially
we push the binary digit formed into the stack, instead of printing it directly. After the entire
number has been converted into the binary form, we pop one digit at a time from the stack and
print it. Therefore we get the decimal number converted into its proper binary form.
Towers of Hanoi
One of the most interesting applications of stacks can be found in solving a puzzle called Tower
of Hanoi. According to an old Brahmin story, the existence of the universe is calculated in terms
of the time taken by a number of monks, who are working all the time, to move 64 disks from
one pole to another. But there are some rules about how this should be done, which are:
Calculators employing reverse Polish notation use a stack structure to hold values. Expressions
can be represented in prefix, postfix or infix notations and conversion from one form to another
may be accomplished using a stack. Many compilers use a stack for parsing the syntax of
expressions, program blocks etc. before translating into low level code. Most programming
languages are context-free languages, allowing them to be parsed with stack based machines.
86
Backtracking
Quicksort
Sorting means arranging the list of elements in a particular order. In case of numbers, it could be
in ascending order, or in the case of letters, alphabetic order.
This is done by using two stacks called LOWERBOUND and UPPERBOUND, to temporarily
store these partitions. The addresses of the first and last elements of the partitions are pushed into
the LOWERBOUND and UPPERBOUND stacks respectively. Now, the above reduction step is
applied to the partitions only after its boundary values are popped from the stack.
A tree is a widely used abstract data type (ADT) or data structure that simulates a hierarchical
structure. A tree data structure can be defined recursively (locally) as a collection of nodes
(starting at a root node), where each node is a data structure consisting of a value, together with a
list of references to nodes (the "children"), with the constraints that no reference is duplicated,
and none points to the root.
Alternatively, a tree can be defined abstractly as a whole (globally) as an ordered tree, with a
value assigned to each node. Both these perspectives are useful: while a tree can be analyzed
mathematically as a whole, when actually represented as a data structure it is usually represented
and worked with separately by node (rather than as a list of nodes and an adjacency list of edges
between nodes, as one may represent a digraph, for instance). For example, looking at a tree as a
whole, one can talk about "the parent node" of a given node, but in general as a data structure a
given node only contains the list of its children, but does not contain a reference to its parent (if
any).
87
Figure 8.3 Binary tree data structure example
In figure 8.3, the node labeled 7 has two children, labeled 2 and 6, and one parent, labeled 2. The
root node (2), at the top, has no parent.
A node is a structure which may contain a value or condition, or represent a separate data
structure (which could be a tree of its own). Each node in a tree has zero or more child nodes,
which are below it in the tree (by convention, trees are drawn growing downwards). A node that
has a child is called the child's parent node (or ancestor node, or superior). A node has at most
one parent.
The topmost node in a tree is called the root node. Depending on definition, a tree may be
required to have a root node (in which case all trees are non-empty), or may be allowed to be
empty, in which case it does not necessarily have a root node. Being the topmost node, the root
node will not have a parent.
All other nodes can be reached from it by following edges or links. (In the formal definition,
each such path is also unique.) In diagrams, the root node is conventionally drawn at the top. In
some trees, such as heaps, the root node has special properties. Every node in a tree can be seen
as the root node of the subtree rooted at that node.
The height of a node is the length of the longest downward path to a leaf from that node. The
height of the root is the height of the tree. The depth of a node is the length of the path to its root
(i.e., its root path).
88
A subtree of a tree T is a tree consisting of a node in T and all of its descendants in T. Nodes thus
correspond to subtrees (each node corresponds to the subtree of itself and all its descendants) –
the subtree corresponding to the root node is the entire tree, and each node is the root node of the
subtree it determines; the subtree corresponding to any other node is called a proper subtree (in
analogy to the term proper subset).
Traversal methods
Stepping through the items of a tree, by means of the connections between parents and children,
is called walking the tree, and the action is a walk of the tree. Often, an operation might be
performed when a pointer arrives at a particular node. A walk in which each parent node is
traversed before its children is called a pre-order walk; a walk in which the children are traversed
before their respective parents are traversed is called a post-order walk; a walk in which a node's
left subtree, then the node itself, and finally its right subtree are traversed is called an in-order
traversal. (This last scenario, referring to exactly two subtrees, a left subtree and a right subtree,
assumes specifically a binary tree.) A level-order walk effectively performs a breadth-first search
search over the entirety of a tree; nodes are traversed level by level, where the root node is
visited first, followed by its direct child nodes and their siblings, followed by its grandchild
nodes and their siblings, etc., until all nodes in the tree have been traversed.
Unlike linear data structures (Array, Linked List, Queues, Stacks, etc) which have only one
logical way to traverse them, trees can be traversed in different ways. Following are the
generally used ways for traversing trees.
89
(b) Preorder
(c) Postorder
Inorder Traversal:
Algorithm Inorder(tree)
1. Traverse the left subtree, i.e., call Inorder(left-subtree)
2. Visit the root.
3. Traverse the right subtree, i.e., call Inorder(right-subtree)
Uses of Inorder
In case of binary search trees (BST), Inorder traversal gives nodes in non-decreasing order. To
get nodes of BST in non-increasing order, a variation of Inorder traversal where Inorder
itraversal s reversed, can be used.
Example: Inorder traversal for the above given figure 8.4 is 4 2 5 1 3.
Preorder Traversal:
Algorithm Preorder(tree)
1. Visit the root.
2. Traverse the left subtree, i.e., call Preorder(left-subtree)
3. Traverse the right subtree, i.e., call Preorder(right-subtree)
Uses of Preorder
Preorder traversal is used to create a copy of the tree. Preorder traversal is also used to get prefix
expression on of an expression tree. Example: Preorder traversal for the above given figure 8.5 is
1 2 4 5 3.
Postorder Traversal:
Algorithm Postorder(tree)
1. Traverse the left subtree, i.e., call Postorder(left-subtree)
2. Traverse the right subtree, i.e., call Postorder(right-subtree)
3. Visit the root.
Uses of Postorder
Postorder traversal is used to delete the tree. Postorder traversal is also useful to get the postfix
expression of an expression tree.
90
Common Application Of Trees
A linked list is a data structure consisting of a group of nodes which together represent a
sequence. Under the simplest form, each node is composed of a data and a reference (in other
words, a link) to the next node in the sequence; more complex variants add additional links. This
structure allows for efficient insertion or removal of elements from any position in the sequence.
Figure 8.6 shows a linked list whose nodes contain two fields: an integer value and a link to the
next node. The last node is linked to a terminator used to signify the end of the list.
Linked lists are among the simplest and most common data structures. They can be used to
implement several other common abstract data types, including lists (the abstract data type),
stacks, queues, associative arrays, and S-expressions, though it is not uncommon to implement
the other data structures directly without using a list as the basis of implementation.
The principal benefit of a linked list over a conventional array is that the list elements can easily
be inserted or removed without reallocation or reorganization of the entire structure because the
data items need not be stored contiguously in memory or on disk. Linked lists allow insertion
91
and removal of nodes at any point in the list, and can do so with a constant number of operations
if the link previous to the link being added or removed is maintained during list traversal.
On the other hand, simple linked lists by themselves do not allow random access to the data, or
any form of efficient indexing. Thus, many basic operations — such as obtaining the last node of
the list (assuming that the last node is not maintained as separate node reference in the list
structure), or finding a node that contains a given datum, or locating the place where a new node
should be inserted — may require scanning most or all of the list elements.
Singly linked lists contain nodes which have a data field as well as a next field, which points to
the next node in the linked list.
In a doubly linked list, each node contains, besides the next-node link, a second link field
pointing to the previous node in the sequence. The two links may be called forward(s) and
backwards, or next and prev(ious).
8.5.5 Arrays
92
An array is a series of elements of the same type placed in contiguous memory locations that can
be individually referenced by adding an index to a unique identifier. This can be illustrated by
the following diagram.
That means that, for example, we can store 5 values of type int in an array without having to
declare 5 different variables, each one with a different identifier. Instead of that, using an array
we can store 5 different values of the same type, int for example, with a unique identifier.
For example, an array to contain 5 integer values of type int called billy could be represented like
this:
where each blank panel represents an element of the array, that in this case are integer values of
type int. These elements are numbered from 0 to 4 since in arrays the first index is always 0,
independently of its length. (Kent, Arrays, 2004)
Like a regular variable, an array must be declared before it is used. A typical declaration for an
array in C++ is:
where type is a valid type (like int, float...), name is a valid identifier and the elements field
(which is always enclosed in square brackets []), specifies how many of these elements the array
has to contain.
Therefore, in order to declare an array called billy as the one shown in the above diagram it is as
simple as:
NOTE: The elements field within brackets [] which represents the number of elements the array
93
is going to hold, must be a constant value, since arrays are blocks of non-dynamic memory
whose size must be determined before execution. In order to create arrays with a variable length
dynamic memory is needed, which is explained later in these tutorials.
Initializing Arrays
When declaring a regular array of local scope (within a function, for example), if we do not
specify otherwise, its elements will not be initialized to any value by default, so their content will
be undetermined until we store some value in them. The elements of global and static arrays, on
the other hand, are automatically initialized with their default values, which for all fundamental
types this means they are filled with zeros.
In both cases, local and global, when we declare an array, we have the possibility to assign initial
values to each one of its elements by enclosing the values in braces { }. For example:
The amount of values between braces { } must not be larger than the number of elements that we
declare for the array between square brackets [ ]. For example, in the example of array billy we
have declared that it has 5 elements and in the list of initial values within braces { } we have
specified 5 values, one for each element.
When an initialization of values is provided for an array, C++ allows the possibility of leaving
the square brackets empty [ ]. In this case, the compiler will assume a size for the array that
matches the number of values included between braces { }:
an array can also be of strings, floats or other datatypes. Take an example. The Declaration
below,
94
string Names[20];
declares an array containing 20 slots or indexes, which can be used to store 20 names. The other
option for this declaration can be as below.
Names[] = {“James”,”Mwape”,”Chibangu”,……..,”Chileshe”}
assuming that the Last name Chileshe is the 20th name In the array. This is basically a list of 20
names.
In any point of a program in which an array is visible, we can access the value of any of its
elements individually as if it was a normal variable, thus being able to both read and modify its
value. The format is as simple as:
Array_name[index]
Following the previous examples in which billy had 5 elements and each of those elements was
of type int, the name which we can use to refer to each element is the following:
For example, to store the value 75 in the third element of billy, we could write the following
statement:
billy[2] = 75;
and, for example, to pass the value of the third element of billy to a variable called a, we could
write:
a = billy[2];
Therefore, the expression billy[2] is for all purposes like a variable of type int.
Notice that the third element of billy is specified billy[2], since the first one is billy[0], the
second one is billy[1], and therefore, the third one is billy[2]. By this same reason, its last
element is billy[4]. Therefore, if we write billy[5], we would be accessing the sixth element of
billy and therefore exceeding the size of the array. We can in the same manner access the values
stores in the Names array. For the example, the statement below displays the name “Chibangu”
95
cout<<Names[2]
In C++ it is syntactically correct to exceed the valid range of indices for an array. This can create
problems, since accessing out-of-range elements do not cause compilation errors but can cause
runtime errors.
1. It is used to represent multiple data items of same type by using only single name.
2. It can be used to implement other data structures like linked lists, stacks, queues, trees,
graphs etc.
3. 2D arrays are used to represent matrices.
4. Data accessing is faster: Using arrays, we can access any data item efficiently just by
specifying the index of that item
1. We must know in advance that how many elements are to be stored in array. They should
be predefined before we use them.
2. Array is static structure. It means that array is of fixed size. The memory which is
allocated to array cannot be increased or reduced.
3. Since array is of fixed size, if we allocate more memory than requirement then the
memory space will be wasted. And if we allocate less memory than requirement, then it
will create problem. In static allocation technique, a fixed amount of memory is allocated
before the start of execution for static arrays and during execution for dynamic arrays.
The memory required for most of the applications often cannot be predicted while writing
a program. If more memory is allocated and the application requires less memory, it
results in wastage of memory space. If less memory space is allocated and if the
applications require more memory space during execution, it is not possible to allocate
extra memory for arrays during execution.
4. The elements of array are stored in consecutive memory locations. So insertions and
deletions are very difficult and time consuming.
96
EXERCISE
a) Trees
b) Queues
c) Stacks
d) Linked lists
e) Arrays
a) Inorder
b) Preorder
c) Postorder
97
UNIT SUMMARY
98
UNIT 9
9.0 Introduction
Testing means verifying correct behavior. Testing can be done at all stages of module
development: requirements analysis, interface design, algorithm design, implementation, and
integration with other modules. In the following, attention will be directed at implementation
testing. Implementation testing is not restricted to execution testing. An implementation can also
be tested using correctness proofs, code tracing, and peer reviews, as described below.
Debugging is a cyclic activity involving execution testing and code correction. The testing that is
done during debugging has a different aim than final module testing. Final module testing aims
to demonstrate correctness, whereas testing during debugging is primarily aimed at locating
errors. This difference has a significant effect on the choice of testing strategies. It is quite
common to confuse the two terms. However, these are two different terms. While debugging
always has to do with code, it is not always the case with testing.
Let’s take a close look at the debugging and the techniques involved therein, then later we shall
look at testing.
99
9.1 Debugging
In order to carry out debugging properly, there are things which should be done first. We can
refer to these as preconditions. What do you think are some of these?
Understand the design and algorithm - If you are working on a module and you do not
understand its design or its algorithms, then debugging will be very difficult. If you don't
understand the design then you can't test the module because you do not know what it is
supposed to do. If you don't understand the algorithms then you will find it very difficult
to locate the errors that are revealed by testing. A second reason for the importance of
understanding algorithms is that you may need that understanding in order to construct
good test cases. This is especially true for algorithms for complex data structures.
Check correctness - There are several methods for checking correctness of an
implementation prior to execution.
Correctness proofs - One useful code check is to examine code using the logical methods
of correctness proofs.
Code tracing - Often, errors can be detected by tracing through the execution of various
calls to module services, starting with a variety of initial conditions for the module. For
poorly understood psychological reasons, tracing works best if you are describing your
tracing to someone else. In order to be effective, tracing of a procedure or function should
be done assuming that calls to other procedures and functions work correctly, even if they
are recursive calls. it can enhance your understanding of algorithms.
Peer reviews - A peer review involves having a peer examine your code for errors. To be
effective, the peer should either already be familiar with the algorithm, or should be given
the algorithm and code in advance. When the reviewer meets with the code writer, the
code writer should present the code with explanations of how it correctly implements the
algorithm. If the reviewer doesn't understand or disagrees with part of the
implementation, they discuss that part until both are in agreement about whether or not it
is an error. The reviewer's role is only as an aid to detecting errors. It is left to the
implementor to correct them.
Anticipate errors - Unfortunately, humans make errors with correctness arguments and
sometimes miss cases in code tracing, and peers don't always catch errors either. So a
programmer should be prepared for some errors remaining in the code after the steps
listed above. Hopefully, there won't be too many.
If these have been fulfilled, what are the requirements for one to carry out proper debugging?
100
9.1.2 Debugging Aids
Assert statements - Some Pascal compilers and all C compilers that meet the ANSI
standard have assert procedures. The assert procedure has a single parameter, which is a
Boolean expression. When a call to assert is executed the expression is evaluated. If it
evaluates to true then nothing happens. If it evaluates to false then the program terminates
with an error message. The assert procedure can be used for detecting and reporting error
conditions.
Tracebacks - Many Pascal compilers generate code that results in tracebacks whenever a
runtime error occurs. A traceback is a report of the sequence of subroutines that are
currently active. Sometimes a traceback will also indicate line numbers in the active
subroutines. If available, a traceback reveals where the runtime error occurred, but it is up
to the programmer to determine where the cause lies.
General purpose debuggers - Many computer systems or compilers come with debugging
programs. Debugging programs provide capabilities for stepping through a program line-
by-line and running a program with breakpoints set by the user. When a line with a
breakpoint is about to be executed the program is interrupted so that the user can examine
or modify program data. Debugging programs also can provide tracebacks in case of run-
time errors. Debuggers are often difficult to learn to use effectively. If they are the only
tool used for debugging then it is likely that they will not save much time. For example,
debugging a data structure module with a debugger, but without a good test driver, will
likely result in spending a lot of time getting piecemeal information about errors.
Incremental testing: In a good design for a complex module, the code is broken up into
numerous subroutines, most of which are no more than 10 to 15 lines long. For a module
designed in this way, incremental testing offers significant advantages.
Sanity checks: Low level code in complex data structure is often written with the
assumption that the higher level code correctly implements the desired algorithm. For
example, the low level code may be written with the assumption that a certain variable or
parameter cannot be NULL. Even if that assumption is justified by the algorithm, it may
still be a good idea to put in a test to see if the condition is satisfied because the higher
level code may be implemented incorrectly. This kind of check is called a sanity check. If
an assert procedure is available then it can be used for the checks. The advantage of
sanity checks is that they give early detection of errors.
Boolean constants for turning debugging code on or off: If debugging code is added to a
module then it is often profitable to enclose it in an if statement that is controlled by a
101
Boolean constant added to the module. By doing this, the debugging code can easily be
turned off, yet be readily available if needed later. Different constants should be used for
different stages of testing so that useless information is minimized.
Error variables for controlling program behavior after errors: When debugging print
statements are added to code, there is the possibility of a tremendous explosion of useless
information. The problem is that a print statement by itself will be executed whether or
not there is an error.
Traceback techniques: To obtain a traceback, use an error Boolean set by sanity checks.
At various places in the module add debug code controlled by the error variable that
prints the current position. Usually it is more economical to first run the code with a
terminating sanity check. Then you only need to add the controlled debug code at places
where the subroutine that contains the sanity check is called.
Testing is an important step in software development life cycle. The process of testing takes
place at various stages of development in programming. This is a vital step in development life
cycle because the process of testing helps to identify the mistakes and sends the program for
correction.
Software testing is the process of evaluation a software item to detect differences between given
input and expected output. Also to assess the feature of A software item. Testing assesses the
quality of the product. Software testing is a process that should be done during the development
process. In other words software testing is a verification and validation process.
Rehman Zafar (2012) explains that Software testing is the process of evaluation a software item
to detect differences between given input and expected output. It is also done to assess the
feature of a software item. Testing assesses the quality of the product. Software testing is a
process that should be done during the development process. In other words software testing is a
verification and validation process.
102
Verification: is the process to make sure the product satisfies the conditions imposed at
the start of the development phase. In other words, to make sure the product behaves the
way we want it to.
Validation: is the process to make sure the product satisfies the specified requirements at
the end of the development phase. In other words, to make sure the product is built as per
customer requirements.
According to Rehman Zafar (2012), there are two basics of software testing: blackbox testing
and whitebox testing.
Black box testing is a testing technique that ignores the internal mechanism of the system and
focuses on the output generated against any input and execution of the system. It is also called
functional testing.
White box testing is a testing technique that takes into account the internal mechanism of a
system. It is also called structural testing and glass box testing.
Black box testing is often used for validation and white box testing is often used for verification.
There are many types of testing. These can fall in either of the two categories ie Whitebox or
blackbox testing. The following are some examples.
Unit Testing
Integration Testing
Functional Testing
System Testing
Stress Testing
Performance Testing
Usability Testing
Acceptance Testing
Regression Testing
Beta Testing
(Zafar, 2012)
103
Unit Testing
Unit testing is the testing of an individual unit or group of related units. It falls under the class of
white box testing. It is often done by the programmer to test that the unit he/she has implemented
is producing expected output against given input.
Integration Testing
Integration testing is testing in which a group of components are combined to produce output.
Also, the interaction between software and hardware is tested in integration testing if software
and hardware components have any relation. It may fall under both white box testing and black
box testing.
Functional Testing
Functional testing is the testing to ensure that the specified functionality required in the system
requirements works. It falls under the class of black box testing.
System Testing
System testing is the testing to ensure that by putting the software in different environments (e.g.,
Operating Systems) it still works. System testing is done with full system implementation and
environment. It falls under the class of black box testing.
Stress Testing
Stress testing is the testing to evaluate how system behaves under unfavorable conditions.
Testing is conducted at beyond limits of the specifications. It falls under the class of black box
testing.
Performance Testing
Performance testing is the testing to assess the speed and effectiveness of the system and to make
sure it is generating results within a specified time as in performance requirements. It falls under
the class of black box testing.
Usability Testing
Usability testing is performed to the perspective of the client, to evaluate how the GUI is user-
friendly? How easily can the client learn? After learning how to use, how proficiently can the
client perform? How pleasing is it to use its design? This falls under the class of black box
testing. (Anonymous, 2005)
104
Acceptance Testing
Acceptance testing is often done by the customer to ensure that the delivered product meets the
requirements and works as the customer expected. It falls under the class of black box testing.
Regression Testing
Regression testing is the testing after modification of a system, component, or a group of related
units to ensure that the modification is working correctly and is not damaging or imposing other
modules to produce unexpected results. It falls under the class of black box testing.
Beta Testing
Beta testing is the testing which is done by end users, a team outside development, or publicly
releasing full pre-version of the product which is known as beta version. The aim of beta testing
is to cover unexpected errors. It falls under the class of black box testing.
EXERSISE
2. What role does testing and debugging play in the program (software) development life
cycle.
4. Discuss the following statement ‘testing does not always have to do with code’.
105
6. Explain 8 types of software testing.
UNIT SUMMARY
106
APPENDIX I
Compiling a program does not really happen as simple as described above. It should be noted
that more is involved and this can be quite a complicated process. Here we will discuss two
process that are vital in program translation ie 1) tokenization and 2) Parsing.
1 def factorial(n):
2 if n == 0:
3 return 1
4 else:
5 return n * factorial(n-1)
For this program text, the tokens would be: def, factorial, (, n, ), :, if, n, ==, and so on. You should
look at tokens as atomic units of program semantics — as opposed to characters. In a very real
sense, the tokenizer defines the vocabulary of the programming language.
107
Tokenizers are very simple programs. Essentially, a tokenizer skips stuff that’s not a token, then
reads stuff that is a token until it can’t anymore, and repeats that over and over again until it runs
out of stuff.
In more detail, a tokenizer “sees” three different kinds of characters: (1) characters that cannot be
part of any token, like whitespace; (2) characters that are the initial character of a token; and (3)
characters that are non-initial characters of a token. A tokenizer reads program text character by
character. As it’s reading, it skips non-token characters, then inspects the first non-skippable
character it finds. If this character is a legal initial token character, it proceeds to read a series of
non-initial token characters until it has read the longest possible token, based on that initial
character; otherwise, it raises an error indicating that it has found an illegal character. This
approach works because the type of token to be read can be determined by inspecting the first
token character the tokenizer sees: a letter for a symbol, a digit for a number, and so on.
2.8.2 Parsing
In general, to parse someone's writing or speech simply means to interpret it. In computers, to
parse is to divide a computer language statement into parts that can be made useful for the
computer. A parser in a program compiler is a program that takes each program statement that a
developer has written and divides it into parts (for example, the main command, options, target
objects, their attributes, and so forth) that can then be used for developing further actions or for
creating the instructions that form an executable program.
Parsing is the problem of transforming a linear sequence of characters into a syntax tree.
Nowadays we are very good at parsing. In other words, we have many tools, such
as lex and yacc, for instance, that helps us in this task. However, in the early days of computer
science parsing was a very difficult problem. This was one of the first, and most fundamental
challenges that the first compiler writers had to face.
If the program text describes a syntactically valid program, then it is possible to convert this text
into a syntax tree. As an example, figure 1.1 contains different parsing trees for three different
programs written in our grammar of arithmetic expressions:
108
Figure 1.1 parsing results into parsing tree (source: wikepedia)
There are many algorithms to build a parsing tree from a sequence of characters. Some are
more powerful, others are more practical. Basically, these algorithms try to find a sequence of
applications of the production rules that end up generating the target string.
109
APPENDIX II
ADVANCED FLOWCHATS STRUCTURES
110
Figure 2.1 Nested Loop Example
The nested while loop is shown here. This example is much simplified, it doesn’t show any
utilization of either of the loops, the outer loop doesn’t do any processing apart from the
processing the inner loop, neither loop shows any statements which will lead to the termination
of the loops.
Each single step through the outer loop will lead to the complete iteration of the outer loop.
Assume that the outer loop counts through 10 steps and the inner loop through 100 steps. The
sequence in the inner loop will be executed 10 * 100 times. Nested loops will do a lot of work.
111
Figure 2.2 Nested Loop
The repeat loop shown here, like the while loop example, is much simplified. It does show two
processes, sequence 1 and sequence 2, one process in the outer loop and one process in the
innner loop
Like the while loop the nested repeat loop will see a great deal of work done. If the outer loop
does a thousand iterations and the inner loops does a thousand iterations then sequence 2 will be
executed 1000 * 1000 times. This teaches you a simple fact a loop can be nested inside another
loop as can be do done even in programs and pseudocode
112
Using multiway selection in flow charts
113
This demonstrates a simple fact that in flowcharting (just like in pseudocode or actual programs)
you may have to face situations where one decision leads to another, and another and so forth.
The flow chart form of multiway selection is shown here.
If decision 1 is true then sequence 1 is executed and the multiway selection is finished. If
decision 1 is false then decision 2 is tested, if this is true then sequence 2 is done and the
multiway selection is finished. If decision 2 is false, you get the picture.
APPENDIX III
RECURSION
Recursion means "defining a problem in terms of itself". This can be a very powerful tool in
writing algorithms. Recursion comes directly from Mathematics, where there are many examples
of expressions written in terms of themselves. For example, the Fibonacci sequence is defined as:
F(i) = F(i-1) + F(i-2)
Recursion is a method of solving problems based on the divide and conquer mentality. The basic
idea is that you take the original problem and divide it into smaller (more easily solved) instances
of itself, solve those smaller instances (usually by using the same algorithm again) and then
reassemble them into the final solution.
The canonical example is a routine to generate the Factorial of n. The Factorial of n is calculated
by multiplying all of the numbers between 1 and n. An iterative solution in C# looks like this:
114
return fact;
}
There's nothing surprising about the iterative solution and it should make sense to anyone
familiar with C#.
The recursive solution is found by recognising that the nth Factorial is n * Fact(n-1). Or to put it
another way, if you know what a particular Factorial number is you can calculate the next one.
Here is the recursive solution in C#:
// In FactRec(5)
return 5 * FactRec( 5 - 1 );
// which is
return 5 * FactRec(4);
If we re-enter the method with the parameter 4 we are again not stopped by the guard clause and
so we end up at:
// In FactRec(4)
return 4 * FactRec(3);
If we substitute this return value into the return value above we get
// In FactRec(5)
return 5 * (4 * FactRec(3));
This should give you a clue as to how the final solution is arrived at so we'll fast track and show
each step on the way down:
115
return 5 * (4 * FactRec(3));
return 5 * (4 * (3 * FactRec(2)));
return 5 * (4 * (3 * (2 * FactRec(1))));
return 5 * (4 * (3 * (2 * (1))));
That final substitution happens when the base case is triggered. At this point we have a simple
algrebraic formula to solve which equates directly to the definition of Factorials in the first place.
It's instructive to note that every call into the method results in either a base case being triggered
or a call to the same method where the parameters are closer to a base case (often called a
recursive call). If this is not the case then the method will run forever.
FIBBONACI RECURSION
Fibonacci sequence is named after Leonardo Fibonacci. Fibonacci numbers starts with the first
two numbers 0 and 1, and each subsequent numbers takes as the sum of its previous two
numbers.
Ex. 0, 1, 1, 2, 3, 5
The first two numbers in the sequence are 0 and 1.
The 3rd number which is 1 is the sum of its previous two numbers - 0 and 1.
The 4th number which is 2 is the sum of its previous two numbers - 1 and 1.
So on and so forth...
/*
Fibonacci series using Recursion
*/
#include <iostream>
116
int main(void)
{
int count;
char waitInput;
cout << "How many numbers in the Fibonacci sequence do you want to show? ";
cin >> count;
cin>>waitInput;
return 0;
}
//fibonacci function
int fibonacci(int num)
{
if (num == 1)
{
return 1;
}
else if (num == 0)
{
return 0;
}
else
{
return fibonacci(num - 1) + fibonacci(num - 2);
}
}
If a recursive method is called with a base case, the method returns a result. If a method is
called with a more complex problem, the method divides the problem into two or more
conceptual pieces: a piece that the method knows how to do and a slightly smaller
version of the original problem. Because this new problem looks like the original
problem, the method launches a recursive call to work on the smaller problem.
For recursion to terminate, each time the recursion method calls itself with a slightly
simpler version of the original problem, the sequence of smaller and smaller problems
must converge on the base case. When the method recognizes the base case, the result is
returned to the previous method call and a sequence of returns ensures all the way up the
line until the original call of the method eventually returns the final result.
117
Both iteration and recursion are based on a control structure: Iteration uses a repetition
structure; recursion uses a selection structure.
Both iteration and recursion involve repetition: Iteration explicitly uses a repetition
structure; recursion achieves repetition through repeated method calls.
Iteration and recursion each involve a termination test: Iteration terminates when the
loop-continuation condition fails; recursion terminates when a base case is recognized.
Iteration and recursion can occur infinitely: An infinite loop occurs with iteration if the
loop-continuation test never becomes false; infinite recursion occurs if the recursion step
does not reduce the problem in a manner that converges on the base case.
Recursion repeatedly invokes the mechanism, and consequently the overhead, of method
calls. This can be expensive in both processor time and memory space.
APPENDIX IV
Inorder sequence: D B E A F C
Preorder sequence: A B D E C F
In a Preorder sequence, leftmost element is the root of the tree. So we know ‘A’ is root for given
sequences. By searching ‘A’ in Inorder sequence, we can find out all elements on left side of ‘A’
are in left subtree and elements on right are in right subtree. So we know below structure now.
A
/ \
/ \
DBE FC
A
/ \
/ \
B C
/\ /
/ \ /
D E F
118
What if we have been given an Inorder and Postorder traversal list, how can go about
constructing the tree?
Inorder is: 2 3 5 7 9 10 11 12
Postorder is: 2 5 3 9 11 12 10 7
Iterate the postorder array in reverse order and keep splitting the inorder array around where that
value is. Do this recursively and that will be your tree. For example:
Look familiar? What is on the left is the left subtree and what is on the right is the right subtree,
in a pseudo-random order as far as the BST structure is concerned. However, you now know
what your root is. Now do the same for the two halves. Find the first occurrence (from the end)
of an element from the left half in the postorder traversal. That will be 3. Split around 3:
7
/
3
This is based on the facts that a value in the postorder traversal will always appear after its
children have appeared and that a value in the inorder traversal will appear between its children
values.
Check the link below for more information on reconstructing tree form the traversal list;
http://cs.stackexchange.com/questions/11015/constructing-a-binary-tree-with-given-traversals
http://www.geeksforgeeks.org/construct-tree-from-given-inorder-and-preorder-traversal/
A binary search tree (BST) is a binary tree where each node has a Comparable key (and an
associated value) and satisfies the restriction that the key in any node is larger than the keys in all
nodes in that node's left subtree and smaller than the keys in all nodes in that node's right subtree.
119
REFERENCES
Algorithms. ( 2014, July 1). Retrieved March 19, 2015, from Tehtarget:
http://whatis.techtarget.com/definition/algorithm
Anonymous. (2005, March 1). Types of software Testing. Retrieved March 23, 2015, from Software
Testing Help: http://www.softwaretestinghelp.com/types-of-software-testing/
Beal, V. (1995). machine language. Retrieved March 19, 2015, from Webopedia:
http://www.webopedia.com/TERM/M/machine_language.html
Farrell, J. A. (1995, August). Anatomy Of a Compiler. Retrieved March 19, 2015, from
http://www.cs.man.ac.uk/~pjj/farrell/comp3.html
Gookin, D. (2010, January 12). How to Use the Switch-Case Structure for Multiple-Choice Decisions in
C Programming. Retrieved March 23, 2015, from tutorialspoint: http://www.dummies.com/how-
to/content/how-to-use-the-switchcase-structure-for-multiplech.html
Janssen, C. (2010, January 11). Structured Programming. Retrieved March 23, 2015, from Technopedia:
http://www.techopedia.com/definition/25972/modular-programming
Kent, J. (2004). C++ Demystified: A Self-Teaching Guide . In J. Kent, C++ Demystified: A Self-
Teaching Guide (p. chapter 9). Osborn: Mc-Graw Hill.
Kent, J. (2004). Arrays. In J. Kent, C++ Demystified: A Self-Teaching Guide (p. Chapter 10). Osborne:
McGraw-Hill.
120
Kent, J. (2004). Nested if Statements. In J. Kent, C++ Demystified: A Self-Teaching Guide (p. Chapter6).
Emeryville, California: McGraw-Hill/Osborne.
Stroustrup, B. (1997). The C++ Programming language Third Edition. Massachusetts: Addison Wesley
Longman, Inc.
Stroustrup, B. (1997). Variables and Data types. In B. Stroustrup, The C++ Programming Language (pp.
69-76). Murray Hill, New Jersey: Addison Wesley Longman, Inc.
Wikipedia. (2006, January 01). Structured Programming. Retrieved March 23, 2015, from Wikepedia:
http://en.wikipedia.org/wiki/Structured_programming
Zafar, R. (2012, March 20). What is software testing? What are the different types of testing? Retrieved
March 23, 2015, from CodeProject: http://www.codeproject.com/Tips/351122/What-is-software-testing-
What-are-the-different-ty
121