1. Computer Programming module
1. Computer Programming module
Chapter One
1. Introduction to programming
What is programming?
Programming is a skill that can be acquired by a computer professional that gives him/her the knowledge
of making the computer perform the required operation or task.
Why do we need to learn computer programming?
Computer programming is critical if one wants to know how to make the computer perform a task. Most
users of a computer only use the available applications on the computer. These applications are produced
by computer programmers. Thus if someone is interested to make such kind of applications, he/she needs
to learn how to talk to the computer, which is learning computer programming.
What is programming language?
A programming language is a language for communication between a person and computer. The content of
communication is known as a program. Programs are set of instructions, which enable a computer to
perform a required operation.
Programming Language: is a set different category of written symbols that instruct computer hardware to
perform specified operations required by the designer.
What skills do we need to be a programmer?
For someone to be a programmer, in addition to basic skills in computer, needs to have the following major
skills:
1. Programming Language Skill: knowing one or more programming language to talk to the computer
First generation (Machine languages, 1940’s): Difficult to program in; they are dependent on machine
languages of the type of computer being used. However, machine language allows the programmer to
interact directly with the hardware, and it can be executed by the computer without the need for a
translator.
Machine language is the ultimate low-level language. To communicate with the first generation computer
programmers had to write programs in machine language: - the 0‘s and 1‘s of binary code. Programming
in 0s and 1s needed reducing statements such as add, subtract and divide into a series of 0‘s and 1‘s.
Programs written in this way are machine-dependent. There is no universal machine language as different
hardware designs dictate different data and memory locations, and hence different bit strings. Programmer
must remember exact memory addresses used to store data and instructions. They execute very quickly and
use memory very efficiently, as no conversion from source code is necessary. Writing the programs is
difficult, tedious, time consuming and hard to debug. A high level of understanding of hardware specifics
is required. All programs written using other languages are translated into machine language before they
can be executed.
End users who wanted applications have to work with specialized programmers who could understand,
think and work directly in the machine language of a particular computer. So programming in machine is
slow and labor intensive process.
Second generation (Assembly languages, appeared in the early 1950’s): Use symbolic names for
operations and storage locations. Assembly language is easier to use than machine language but it is still
difficult to understand. A systems program called an assembler translates it into machine language.
Different computer architectures have their own machine and assembly languages, which means that
programs written in these languages are not portable to other, incompatible systems. Many programmers
still use assembly languages because they still give them close control over the hardware.
Instead of using 0‘s and 1‘s programmers substituted language like acronyms and
words such as add, sub(subtract) in programming statements.
§ Costly in terms of programmer time
§ Difficult to read and debug, and
§ Difficult to learn
§ Highly used in system software development
Programs are easier to create and to debug than machine language, but are still prone to errors and
tedious and execute faster than high-level languages.
Third generation (High-level languages, emerged from 1950’s - 1970’s): Use English-like instructions
like print and mathematicians were able to define variables with statements such as Z=A+B. Many high-
level languages are portable. Each has syntax rules that must be followed. Such languages are much easier
to use than assembly language but they can take considerable time to learn. Two types of systems
programs exist for translating them into machine language: interpreters and compilers.
In High-level languages, instructions closely resemble human language and mathematical notation.
Programmers do not require detailed knowledge of hardware specifics as these languages extensively use
symbolic representations of memory addresses and library functions. The use of common words (reserved
words) within instructions makes them easier to learn. Assembly language code segments may be added to
most high-level programs, where faster execution speed is required by the programmer. There are two
types of language-translator programs used to translate into machine code, Interpreters and Compilers.
Fourth-generation (Since late 70’s): Have simple, English-like syntax rules; commonly used to
access databases. As we mentioned earlier, the third-generation programming languages discussed
in the previous section are all procedural languages because the programmer must list each step
and must use logical control structures to indicate the order in which instructions are to be executed.
Fourth-generation languages (4GLs), on the other hand, are nonprocedural languages. These
languages can be compared to the way in which you might instruct someone to cook a meal. The
nonprocedural method is simply to state the needed output: fix a meal of chicken, rice, and salad.
Using the procedural method, on the other hand, involves specifying each step - from preparing the
shopping list to washing the dishes.
Obviously, the nonprocedural method is easier to write, but you have less control over how each task is
actually performed. For example, the dishes might be washed by hand or in a dishwasher. When using
nonprocedural languages, the methods used and the order in which each task is carried out are left to the
language itself; the user does not have any control over it. In addition, 4GLs sacrifice computer efficiency
in order to make programs easier to write; hence they require more computer power and processing time.
As the power and speed of hardware have increased and its cost has decreased, the use of 4GLs has spread.
Because fourth-generation languages have a minimum number of syntax rules, people who have not been
trained as programmers can use such languages to write application programs, as they need them. This
saves time and fees professional programmers for more complex tasks. There are several categories of
4GLs languages. The most common once are: query languages, report generators, and application
generators and graphic languages.
Query languages allow the user to retrieve information from databases by following simple syntax rules.
For example, you might ask the database to locate all customer accounts that are more than 90 days
overdue. Example of query languages is SQL, which has become a de facto standard.
Fifth-generation (1990’s): Used in artificial intelligence and expert systems; also used for accessing
databases. Fifth-generation languages (5GLs) are also nonprocedural languages and are also commonly
used to query databases. Because these languages are still in their infancy, only a few are currently
commercially available. They are closely tied to artificial intelligence and expert systems.
Fifth-generation languages are the ―natural‖ languages whose instructions closely resemble human speech
"Get me Debela‘s sales figures for the 1997 financial year" is a typical instruction. Very powerful hardware
and software are required to execute such programs because of the complexity involved in interpreting
commands entered in human language. This means computers can in the future have the ability to
think for themselves and draw their own inferences using programmed information in large
databases. Complex processes like understanding speech would appear to be trivial using these fast
inferences and would make the software seem highly intelligent.
True problem situations, either real or anticipated, that require corrective action
Unexploited Opportunities to improve a situation despite the absence of complaints
Directives to change a situation regardless of whether anyone has complained about the
current situation
Problem solving is the process of transforming the description of a problem into the solution of that
problem by using our knowledge of the problem domain and by relying on our ability to select and use
appropriate problem-solving strategies, techniques, and tools.
Problem Solving: is basic intellectual process that has been refined and systemized for the various
challenges people face.
Top down design: is a systematic approach based on the concept that the structure of the problem should
determine the structure of the solution and what should be done in lower level. This approach will try to
disintegrate a larger problem into more smaller and manageable problems to narrow the problem domain.
Bottom up design: is the reverse process where the lowest level component are built first and the system
builds up from the bottom until the whole process is finally completed.
Algorithm development
An algorithm is procedure for solving a problem in terms of
the action to execute (what to do) and
the order in which these actions are executed(done)
An algorithm needs to be
Precise and unambiguous (no ambiguity in any instruction and in the order of execution)
Simple
Correct
Finite (has to have an end)
Produce expected output
Efficient: in time, memory and other resources
An algorithm can be expressed in many ways. Some of these methods are narrative, flowchart and
pseudo-code: Narrative: often used to narrate the algorithm, can be understood by any user who may
not have any knowledge of computer programming. Too wordy, too unambiguous and can be interpreted in
different ways.Example: Accept salary of the employee. Calculate bonus as 10% of salary and add it to
salary. Accept service year of employee. If the service year is greater than 10, give additional 100 birr as
bonus. Display the bonus of the employee.
Flowcharts: a diagram consisting of labeled symbols, together with arrows connecting one symbols to
another.
Basic flowcharting symbols are:
Start
Read NAME,
BALANCE, RATE
Interest=BALANCE *RATE
Display NAME,
INTEREST
Stop
2) A program that identifies a larger and smaller number from two numbers
Start
Read A, B
Yes Big=B
A<B?
Small=A
No
Big=A
Small=B
Stop
Yes
MARK>80 ? GRADE-A
No
Yes GRADE-B
MARK>60 ?
No
Yes GRADE-C
MARK>50 ?
No
Yes GRADE-D
MARK>40 ?
No
GRADE-F
Increment Count
No
Count>10 ?
yes
Display NAME, GRADE Stop
Pseudo-code:
It is much similar to real code. We use verbs to write pseudo-code. Capitalize important words that
show actions.
Eg 1) A pseudo-code to calculate interest rate
ACCEPT Name, Principal, Rate
Interest=Principal X Rate
DISPLAY Name, Interest
2) A pseudo-code to calculate bonus
ACCEPT Name, Salary
Bonus=SalaryX0.1
ACCEPT Serviceyear
IF Serviceyear>10 Then
Bonus+100
ENDIF
DISPLAY Bonus
3) A pseudo-code that calculates grade
ACCEPT Mark, Name
IF Mark>80 Then
GradeA
ELSE IF Mark>=70 Then
GradeB
ELSE IF Mark>=60 Then
GradeC
ELSE IF Mark>=50 Then
GradeD
ELSE
GradeF
ENDIF
DISPLAY Grade, Name
Worksheet 1
For each of the problems below, develop a flow chart
Chapter Two
Global declaration Section: variables declared under this section are available throughout
the program.
Class declaration Section: defines the class declaration.
Functions: The function main, which has been written in the program, is an example of
function. A function is defined as group of instructions, which are assigned a name and
accessed by the name.
Syntax:
The semantics of a programming language deal with the meanings given to syntactically
correct constructs of the language. Usually, semantics is defined in terms of the program‟s
run-time behavior: What happens when the program is executed with a certain set of inputs,
what statements are executed, what values are assigned to the variables, and what output is
produced.
Any C++ program file should be saved with file name extension “ .CPP ”
Type the program directly into the editor, and save the file as hello.cpp, compile it and
then run it. It will print the words Hello World! on the computer screen.
The first character is the #. This character is a signal to the preprocessor. Each time you
start your compiler, the preprocessor runs through the program and looks for the hush or
sharp (#) symbols and act on those lines before the compiler runs.
The include instruction is a preprocessor instruction that directs the compiler to include a
copy of the file specified in the angle brackets in the source code.
Page 13 of 103 BU Department of Computer Science
Fundamentals of Computer Programming
If the path of the file is not specified, the preprocessor looks for the file under
c:\tc\include\ folder or in include folder of the location where the editor is stored.
The effects of line 1, i.e. include<iostream.h> is to include the file iostream.h into the
program as if the programmer had actually typed it.
When the program starts, main() is called automatically.
Every C++ program has a main() function.
The return value type for main() here is void, which means main function will not return a
value to the caller (which is the operating system).
The main function can be made to return a value to the operating system.
The Left French brace “{“signals the beginning of the main function body and the
corresponding Right French Brace “}” signals the end of the main function body. Every
Left French Brace needs to have a corresponding Right French Brace.
The lines we find between the braces are statements or said to be the body of the function.
A statement is a computation step which may produce a value or interact with input and
output streams.
The end of a single statement ends with semicolon (;).
The statement in the above example causes the string “Hello World!” to be sent to the
“cout” (VDU) stream which will display it on the computer screen.
The user of the program should supply correct form of data when it is taken as input from the
keyboard. If the input value is different from the variable‟s data type or capacity, then there is
a possibility of erroneous result and erratic behavior of the program.
Both << and >> return their right operand as their result, enabling multiple input or
multiple output operations to be combined into one statement. The following example will
illustrate how multiple input and output can be performed:
E.g.:
cin>>var1>>var2>>var3;
Here three different values will be entered for the three variables. The input
should be separated by a space, tab or newline for each variable.
It is equivalent to
cin>>var1;
cin>>var2;
cin>>var3;
cout<<var1<<”, “<<var2<<” and “<<var3;
Here the values of the three variables will be printed where there is a “,”
(comma) between the first and the second variables and the “and” word
between the second and the third.
ii. Multiple Line Comment: Anything enclosed by the pair /* and */ is considered a
comment. Eg:
/*this is a kind of comment where
Multiple lines can be enclosed in
one C++ program */
Comments should be used to enhance (not to hinder) the readability of a program. The following
two points, in particular, should be noted:
i. A comment should be easier to read and understand than the code which it tries to explain.
A confusing or unnecessarily-complex comment is worse than no comment at all.
ii. Over-use of comments can lead to even less readability. A program which contains so much
comment that you can hardly see the code can by no means be considered readable.
iii. Use of descriptive names for variables and other entities in a program, and proper
indentation of the code can reduce the need for using comments.
Data Type: a type which is established when the variable is defined. (e.g. integer,
real, character etc). Data type describes the property of the data and the size of the
reserved memory. A variable can hold data in either of these types: a number or a
character. The number may be an integer or a number with a decimal point (floating point),
and the data size may be small or large. Data type is all about this.
Name: a name which will be used to refer to the value in the variable. A unique
identifier for the reserved memory location
Value: a value which can be changed by assigning a new value to the variable.
Data Types
Type Length Range
Unsigned Signed
Binary Decimal Binary Decimal
0 0 0 0 →0 0 0 0 0 →0
0 0 0 1 →1 0 0 0 1 →1
0 0 1 0 →2 0 0 1 0 →2
0 0 1 1 →3 0 0 1 1 →3
0 1 0 0 →4 0 1 0 0 →4
0 1 0 1 →5 0 1 0 1 →5
0 1 1 0 →6 0 1 1 0 →6
0 1 1 1 →7 0 1 1 1 →7
1 0 0 0 →8 1 0 0 0 →0
1 0 0 1 →9 1 0 0 1 → -1
Page 17 of 103 BU Department of Computer Science
Fundamentals of Computer Programming
1 0 1 0 →10 1 0 1 0 → -2
1 0 1 1 →11 1 0 1 1 → -3
1 1 0 0 →12 1 1 0 0 → -4
1 1 0 1 →13 1 1 0 1 → -5
1 1 1 0 →14 1 1 1 0 → -6
1 1 1 1 →15 1 1 1 1 → -7
In the above example, in case of unsigned, since all the 4 bits can be used to represent the
magnitude of the number the maximum magnitude that can be represented will be 15 as
shown in the example.
If we use signed, we can use the first bit to represent the sign where if the value of the
first bit is 0 the number is positive if the value is 1 the number is negative. In this case we
will be left with only three bits to represent the magnitude of the number. Where the
maximum magnitude will be 7.
Declaring Variables
Variables can be created in a process known as declaration.
Syntax: Datatype Variable_Name;
The declaration will instruct the computer to reserve a memory location with the name
and size specified during the declaration.
Good variable names indicate the purpose of the variable or they should be self
descriptive.
E.g. int myAge; //variable used to store my age
If you are going to declare more than one variable of the same type, you can declare all of
them in a single statement by separating their identifiers with commas. For example:
int a, b, c ;
This declares three variables (a, b, c), all of them of type int, and has exactly the same as:
int a;
int b;
int c;
Identifiers
Identifiers: - name given to any programming element (like variables, functions, arrays, structures,
arguments, classes, pointers etc) is known as identifiers. Identifiers are the fundamental requirement
of any languages. They are named by the programmer (but by keeping the rules for giving names). A
name should consist of one or more characters, each of which may be a letter (i.e., 'A'-'Z' and 'a' - 'z'), a
digit i.e., '0'-'9'), or an underscore character ('_').
A valid identifier is a sequence of one or more letters, digits or underscores symbols. The
length of an identifier is not limited.
Neither space nor marked letters can be part of an identifier.
Only letters, digits and underscore characters are valid.
The first character must be a letter or underscore (They can never begin with a digit).
It should not be a keyword.
It should not have special characters (except the underscore)
Special characters: include:
Punctuation marks like .,;,:,?,, etc
Arithmetic operators like +,-,*,/,%
Others like =,(,{,[,$,’,”,# ,& etc
Note: the C ++ language is “case sensitive “, that means that an identifier written in capital
letters is not equivalent to another one with the same name but written in small letters. E.g.
the variable Age is not identical with variable age.
Initializing Variables
When declaring a variable, its value is by default undetermined. But you may want a
variable to store a concrete value at the same moment that it is declared. In order to do
that, you can initialize the variable.
e.g. int a = 0;
or: int a;
a=0;
Scope of Variables
Scope of a variable is the boundary or block in a program where a variable can be
accessed. The boundary or block is identified by the left and right French brackets.
Page 19 of 103 BU Department of Computer Science
Fundamentals of Computer Programming
In C++, we can declare variables anywhere in the source code. But we should declare a
variable before using it no matter where it is written.
There are 2 types of variable visibilities. These are:-
i. Global variables: are variables that can be referred/ accessed anywhere in the code,
within any function, as long as it is declared first. A variable declared before any
function immediately after the include statements are global variables.
ii. Local Variables: the scope of the local variable is limited to the code level or block
within which they are declared.
In the following example, the integer data type num1 is accessible everywhere whereas z
and is only accessible in the add function and num2 is accessible in main function. This
means cout<<z; or any statement involving z is only valid in add function. E.g:
#include<iostream.h>
int num1;
int add( int x, int y)
{ int z;
….
}
int main()
{ unsigned short age;
float num2;
cout<<”\n Enter your age:”;
…
}
In C++ the scope of a local variable is given by the block in which it is declared.
If it is declared within a function, it will be a variable with a function scope. If it is
declared in a loop, its scope will be only in the loop, etc.
Characters
Characters variables (type char) are typically one byte in size, enough to hold 256 different
values. A char can be represented as a small number (0 - 255).
Char in C++ are represented as any value inside a single quote.
E.g.: „x‟, „A‟, „5‟, „a‟, etc.
When the compiler finds such values (characters), it translates back the value to the ASCII
values. E.g. „a‟ has a value 97 in ASCII.
\t tab
\b backspace
\” double quote
\‟ single quote
\? Question mark
\\ backslash
2.5.2 Constants
A constant is any expression that has a fixed value.
Like variables, constants are data storage locations in the computer memory. But,
constants, unlike variables their content can not be changed after the declaration.
Constants must be initialized when they are created by the program, and the programmer
can‟t assign a new value to a constant later.
C++ provides two types of constants: literal and symbolic constants.
i. Literal constant: is a value typed directly into the program wherever it is needed.
E.g.: int num = 43;
Enumerated constants
Used to declare multiple integer constants using a single line with different features.
Enables programmers to define variables and restrict the value of that variable to a set of
possible values which are integer.
The enum type cannot take any other data type than integer
enum types can be used to set up collections of named integer constants. (The keyword
enum is short for “enumerated''.)
The traditional way of doing this was something like this:
#define SPRING 0
#define SUMMER 1
#define FALL 2
An alternate approach using enum would be
enum SEASON{ SPRING, SUMMER, FALL, WINTER };
You can declare COLOR to be an enumeration, and then you can define five possible
values for COLOR: RED, BLUE, GREEN, WHITE and BLACK.
E.g.: enum COLOR {RED,BLUE,GREEN,WHITE,BLACK};
Every enumerated constant has an integer value. If the programmer does not specify
otherwise, the first constant will have the value 0, and the values for the remaining
constants will count up from the initial value by 1. thus in our previous example RED=0,
BLUE=1, GREEN=3, WHITE=4 and BLACK=5
But one can also assign different numbers for each.
E.g.: enum COLOR{RED=100,BLUE,GREEN=500,WHITE,BLACK};
Where RED will have 100 and BLUE will have 101 while GREEN will have 500, WHITE 501 and
BLACK 502.
PI float constant that returns the value 3.14 if the constant is defined.
secondsPerMinute integer constant that returns 60 if the constant is declared
E.g.2: complicated expressions:
x = a + b;
y = x = a + b;
The second line is evaluated in the following order:
1. add a to b.
2. assign the result of the expression a + b to x.
3. assign the result of the assignment expression x = a + b to y.
2.6 Operators
An operator is a symbol that makes the machine to take an action.
Different Operators act on one or more operands and can also have different kinds of operators.
C++ provides several categories of operators, including the following:
Assignment operator
Arithmetic operator
Relational operator
Logical operator
Increment/decrement operator
Conditional operator
Comma operator
The size of operator
Explicit type casting operators, etc
Assignment operator (=)
The assignment operator causes the operand on the left side of the assignment statement to
have its value changed to the value on the right side of the statement.
Syntax: Operand1=Operand2;
Operand1 is always a variable
Operand2 can be one or combination of:
A literal constant: Eg: x=12;
A variable: Eg: x=y;
An expression: Eg: x=y+2;
Compound assignment operators (+=, -=, *=, /=, %=, >>=, <<=, &=, ^=)
Compound assignment operator is the combination of the assignment operator with
other operators like arithmetic and bit wise operators.
The assignment operator has a number of variants, obtained by combining it with other
operators.
E.g.:
value += increase; is equivalent to value = value + increase;
a -= 5; is equivalent to a = a – 5;
a /= b; is equivalent to a = a / b;
price *= units + 1 is equivalent to price = price * (units + 1);
And the same is true for the rest.
To obtain a real division when both operands are integers, you should cast one of the
operands to be real.
E.g.:
int cost = 100;
Int volume = 80;
Double unitPrice = cost/ (double) volume;
The module(%) is an operator that gives the remainder of a division of two integer values.
For instance, 13 % 3 is calculated by integer dividing 13 by 3 to give an outcome of 4 and a
remainder of 1; the result is therefore 1.
E.g.:
a = 11 % 3
a is 2
Relational operator (==, !=, > , <, >=, <=)
In order to evaluate a comparison between two expressions, we can use the relational operator.
The result of a relational operator is a bool value that can only be true or false according to
the result of the comparison.
E.g.:
(7 = = 5) would return false or returns 0
(5 > 4) would return true or returns 1
The operands of a relational operator must evaluate to a number. Characters are valid
operands since they are represented by numeric values. For E.g.:
„A‟ < „F‟ would return true or 1. it is like (65 < 70)
Logical AND (&&) produces 0 if one or both of its operands evaluate to 0 otherwise it
produces 1.
Logical OR (||) produces 0 if both of its operands evaluate to 0 otherwise, it produces 1.
E.g.:
!20 //gives 0
10 && 5 //gives 1
10 || 5.5 //gives 1
10 && 0 // gives 0
N.B. In general, any non-zero value can be used to represent the logical true, whereas only
zero represents the logical false.
First operand1 is a relational expression and will be evaluated. If the result of the
evaluation is non zero (which means TRUE), then operand2 will be the final result.
Otherwise, operand3 is the final result.
E.g.: General Example
Z=(X<Y? X : Y)
This expression means that if X is less than Y the value of X will be assigned to Z otherwise (if
X>=Y) the value of Y will be assigned to Z.
E.g.:
int m=1,n=2,min;
min = (m < n ? m : n);
E.g.:
(7 = = 5 ? 4: 3) returns 3 since 7 is not equal to 5
Here, when m is less than n, mCount++ is evaluated and the value of m is stored in min.
otherwise, nCount++ is evaluated and the value of n is stored in min.
The sizeof() Operator
This operator is used for calculating the size of any data item or type.
It takes a single operand (e.g. 100) and returns the size of the specified entity in bytes. The
outcome is totally machine dependent.
E.g.:
a = sizeof(char)
b = sizeof(int)
c = sizeof(1.55) etc
Operator Precedence
The order in which operators are evaluated in an expression is significant and is
determined by precedence rules. Operators in higher levels take precedence over
operators in lower levels.
Precedence Table:
* / % Left to right
+ - Left to right
== != Left to right
|| Left to right
? : Left to right
= ,+=, -=, *=, /=,^= ,%=, &= ,|= ,<<= ,>>= Right to left
, Left to right
E.g.
a==b+c*d
c * d is evaluated first because * has a higher precedence than + and = =.
Operators with the same precedence level are evaluated in the order specified by the
column on the table of precedence rule.
Worksheet 2
For each of the problems write a C++ code to perform the required task. Your program should be
based on the flow chart you drawn in the first worksheet.
16) Read an integer value from the keyboard and display a message indicating if this number is
odd or even.
17) read 10 integers from the keyboard in the range 0 - 100, and count how many of them are
larger than 50, and display this result
18) Take an integer from the user and display the factorial of that number
Spotting errors
For each of the following programs, spot the flaws:
Program 1
/ this program will calculate the area of a square
#include <iostream.h>
void main()
{
int area; / store calculated area of square
int side; / input length of side of square
cout << "How wide is the square?" << endl;
cin >> side;
area = side * side;
cout << "The square has area area" << endl;
}
Program 2
// this program prints information about the author
void main()
{
cout << 'This program was written by Dave Wessels';
cout << 'He didn't do a great job of it, ' << endl;
cout << 'It won't even compile';
}
// this program calculates user age
#include <iostream.h>
int main()
int currentyear;
int birthyear;
cout << "Enter the year you were born" << endl;
cin >> birthyear;
cout << "Enter the current year" << endl;
cin >> currentyear;
age = currentyear - birthyear;
cout << "This year you will be" << age << endl;
}
Page 29 of 103 BU Department of Computer Science
Fundamentals of Computer Programming
Program 3
// given the radius of a circle,
// this program prints its circumference,
// and prints its area to three decimal places
#include <iostream.h>
#include <iomanip.h>
void mian()
(
int radius; // input circle radius
int circumference; // calculated circumference
float area; // calculated area
cout << "Enter the integer radius of the circle";
cout << endl;
cin >> radius;
circumference = 2 * radius * Pi;
area = Pi * raduis * radius;
Chapter Three
3. Flow of Control
A running program spends all of its time executing instructions or statements in that program.
The order in which statements in a program are executed is called flow of that program.
Programmers can control which instruction to be executed in a program, which is called flow control.
This term reflects the fact that the currently executing statement has the control of the CPU, which when
completed will be handed over (flow) to another statement.
Flow control in a program is typically sequential, from one statement to the next.
But we can also have execution that might be divided to other paths by branching statements. Or perform a
block of statement repeatedly until a condition fails by Repetition or looping.
Depending upon requirement of the problem, it is often required to alter the normal sequence of execution in
the program. This means that we may desire to selectively or repetitively execute a program statement.
Flow control is an important concept in programming because it will give all the power to the programmer to
decide what to do to execute during a run and what is not, therefore, affecting the overall outcome of the
program.
Sequential Statements
Such kinds of statements are instruction in a program which will be executed one after the other in the order
scripted in the program. In sequential statements, the order will be determined during program development
and cannot be changed.
A number of C++ structure known as control structures are available for the flow of processing.
3.1 Selection Statements/Conditional statements
Selection statements are statements in a program where there are points at which the program will decide at
runtime whether some part of the code should or should not be executed.
They are mainly used for making decisions. Depending on the value of an expression decision can be made.
There are two types of selection statements in C++, which are the ―if statement‖ and the ―switch statement‖
3.1.1 The if Statement
It is sometimes desirable to make the execution of a statement dependent upon a condition being satisfied.
The different forms of the ‗If‖ statement will be used to decide whether to execute part of the program based
on a condition which will be tested either for TRUE or FALSE result.
The different forms of the ―If‖ statement are:
The simple if statement
The if else statement
The if else if statement
In any ―if‖ statement, first the ―expression” will be evaluated and if the outcome is non zero (which means
TRUE), then the ―statements” is executed. Otherwise, nothing happens (the statement will not be executed)
and execution resumes to the line immediately after the ―if‖ block.
Page 31 of 103 BU Department of Computer Science
Fundamentals of Computer Programming
To make multiple statements dependent on the same condition we can use a compound statement, which will
be implemented by embracing the group of instructions within the left ―{― and right ―}‖ French bracket.
The following diagram shows the execution of if statement.
Expressi False
on
True
Body of if
E.g. if(age>18)
cout<<‖you are an adult‖;
E.g.:
if(balance > 0)
{
interest = balance * creditRate;
balance += interest;
}
Most of the time ―expression” will have relational expressions testing whether something is equal, greater,
less, or different from something else.
It should be noted that the output of a relational expression is either True (represented by anything different
from zero) or False (represented by Zero).
Thus any expression, whose final result is either zero or none zero can be used in ‖expression‖
E.g.:
int x;
cin>>x;
if(x)
cout<<‖you are an adult‖;
In the above example, the value of variable x will be an input from the user. The ―if‖ statement will be true if
the user gives anything different from zero, which means the message ―you are an adult‖ will be displayed
on the screen. If the user gives zero value for x, which will be interpreted as False, nothing will be done as
the if statement is not satisfied.
Thus, expression can be:
Relational expression,
A variable,
A literal constant, or
Assignment operation, as the final result is whatever we have at the right hand side and the one at the
left hand side is a variable.
The if else statement
Another form of the ―if‖ is the ―if …else‖ statement.
The ―if else‖ statement allows us to specify two alternative statements:
One which will be executed if a condition is satisfied and
Another which will be executed if the condition is not satisfied.
Page 32 of 103 BU Department of Computer Science
Fundamentals of Computer Programming
First ―expression‖ is evaluated and if the outcome is none zero (true), then ―statements1‖ will be executed.
Otherwise, which means the ―expression” is false ―statements2” will be executed.
The following diagram shows the execution of if else statement.
Expressi
on False
True
Body of else
Body of if
E.g.: E.g.2:
if(balance > 0) int x;
{ cout<<‖Enter a number: ―;
interest = balance * creditRate; cin>>x;
balance += interest; if(x%2==0)
}
cout<<‖The Number is Even‖;
else
else
{
interest = balance * debitRate; cout<<‖The Number is Odd‖;
balance += interest; E.g.3:
} int x;
E.g.1: cout<<‖Enter a number: ―;
if(age>18) cin>>x;
cout<<‖you are an adult‖; if(x%2)
else cout<<‖The Number is Odd‖;
cout<<‖You are a kid‖; else
cout<<‖The Number is Even‖;
else
charge = 5 * tarif1 + (callDuration - 5) * tarif2;
}
else
charge = flatFee;
E.g:
#include<iostream.h>
#include<conio.h>
int main()
{
int testScore;
cout<<‖\nEnter your test score:‖;
cin>>testScore;
False True
testScore < 70?
First ―expression1‖ is evaluated and if the outcome is none zero (true), then ―statements1‖ will be executed.
Otherwise, which means the ―expression1” then ―expression2” will be evaluated: if the out put of
expression2 is True then ―statements2” will be executed otherwise the next ―expression” in the else if
statement will be executed and so on.
If all the expressions in the ―if‖ and ―else if‖ statements are False then ―statements” under else will be
executed.
The ―if…else‖ and ―if…else if‖ statements are said to be exclusive selection as if one of the condition
(expression) is satisfied only instructions in its block will be executed and the rest will be ignored.
E.g.:
if(score >= 90)
cout<< ―\n your grade is A‖;
else if(score >= 80)
cout<< ―\n your grade is B‖;
else if(score >= 70)
cout<< ―\n your grade is C‖;
else if(score >= 60)
cout<< ―\n your grade is D‖;
else
cout<< ―\n your grade is F‖;
In the above example, only one of the five cout statements will be executed and the rest will be ignored. But
until one of the conditions is satisfied or the else part is reached, the expressions will be tested or evaluated.
StatementsN will be executed if and only if ―expression1‖ and ―expression2‖ are evaluated and if the
outcome of both is none zero (TRUE).
StatementsM will be executed if and only if ―expression1‖ is TRUE and ―expression2‖ is FALSE.
StatementsR will be executed if and only if ―expression1‖ is FALSE and ―expression3‖ is TRUE.
Page 35 of 103 BU Department of Computer Science
Fundamentals of Computer Programming
StatementsT will be executed if and only if ―expression1‖ is FLASE and ―expression2‖ is FALSE.
Lets have an example on nested if statements
#...
int main()
{
int testScore, age;
cout<<‖\n Enter your test score :‖;
cin>>testScore;
cout<<―\n enter your age:‖;
cin>>age;
if(testScore >= 70)
{
if(age < 10)
cout<<―\n You did a great job‖;
else
cout<<―\n You did pass‖;
}
else
cout<<―\n You did not pass‖;
getch();
return 0;
}
The above program can be expressed diagrammatically as follows.
False True
testScore
>=70?
True
False False
True
cout<</;you didn’t pass”; age < 10?
switch (N){
switch(N){
case 1: x=10;
case 1: x=10; break;
case 2: x=20;
case 2: x=20; break;
case 3: x=30;
case 3: x=30; break;
}
}
Even if N is 1 or 2 x will have 30
X will have 10, 20 or 30 based on the value of N
True True
N==1? x = 10
N==1? x = 10
False
break
False
True True
N==2? x =20 N==2? x = 20
False false
True True
break
False False
N==3? x = 30 N==3? x = 30
break
The break terminates the switch statement by jumping to the very end of it.
There are, however, situations in which it makes sense to have a case without a break. For instance:
E.g.: switch(operator)
{
case ‗+‘: result = operand1 + operand2;
break;
case ‗-‘ : result = operand1 – operand2;
break;
case ‗x‘:
case ‗*‘: result = operand1 * operand2;
break;
case ‗/‘: result = operand1 / operand2;
break;
default: cout<<― unknown operator:‖<<operator<<―\n‖;
}
Because case ‗x‘ has no break statement (in fact no statement at all!), when this case satisfied, execution
proceeds to the statements of the next case and the multiplication is performed.
Switch evaluates expression and compares the result to each of the case values.
Relational and Boolean operators can be used in switch tag if and only if the expected output is either 0 to
represent False or 1 to represent True as that is the only possible output from such operators.
return 0;
}
Even though it is not recommended, expression1, expression2 and expression3 can be optional or can be
ignored. This means that they can take NULL statement.
But making expression2 null means that the loop will not terminate. In such cases one can include an ―if‖
statement inside the ―for‖ loop which will test a condition and break out from the loop using the break
statement.
While making one or more of the three expressions null, the semi colons CAN NOT be ignored.
E.g.:
for (;n<10;) //if we want neither initialization nor increase/decrease
for ( ; ; ) //is an infinite loop unless and otherwise there is if statement inside the loop.
It is declared above that expression1 and expression3 can be one or more statements. The composite
statements should be separated by a comma. This means, optionally, using the comma operator (,) we can
specify more than one instruction in any of the two fields included in a ―for‖ loop.
E.g.
for(n=0,i=100;n!=i; n++,i--)
{
//whatever here
In the above example, n=0 and i=100 will be part of expression1 and will be executed only once before the
loop starts. In addition, n++ and i—will be part of expression3 and will be executed after each
looping/iteration.
Eg:1
//the following for statement adds the numbers between 0 and n
int Sum=0;
for(int i=0; i<=n;i++)
Sum=Sum+i;
Eg:2
//the following for statement adds the even numbers between 0 and n
int Sum=0;
for(int i=0; i<=n;)
{
Sum=Sum+i;
i+=2;
}
Eg:3
//the following for statement adds the even numbers between 0 and n
//where all the three expressions are null.
int Sum=0;
int i=0;
for( ; ; )
{
If(i<=n)
break;
else
{
Sum=Sum+i;
i++;
}
}
In the above example, the initialization is at the top before the looping starts, the condition is put in if
statement before the instructions are executed and the increment is found immediately after the statements to
be executed in the loop.
NB: even though there is the option of making all the three expressions null in a ―for‖ loop, it is not
recommended to make the condition to take null statement.
First expression (called the loop condition) is evaluated. If the outcome is non zero then statement (called the
loop body) is executed and the whole process is repeated. Otherwise, the loop is terminated.
Suppose that we wish to calculate the sum of all numbers from 1 to some integer value n. This can be
expressed as :
E.g.1:// adds the numbers between 0 and any given number n
i=1;
sum = 0;
while(i <= n)
sum += i++;
while(expression);
First statement is executed and then expression is evaluated. If the outcome of the expression is nonzero,
then the whole process is repeated. Otherwise the loop is terminated.
E.g.:
//our previous example (Eg3) in the while loop might be changed as:
age=-1;
do
{
cout<<“\n enter your valid age [between 0 and 130]:”;
cin>>age;
}
while(age < 0 || age > 130);
int product = 0;
while(product < 50)
product *= 5;
E.g.2:
//Do you know why the following is an infinite loop?
int counter = 1;
while(counter != 10)
counter += 2;
In the first example, since product is initialized with zero, the expression ―product*=5‖ will always give us
zero which will always be less than 50.
In the second example, the variable counter is initialized to 1 and increment is 2, counter will never be equal
to 10 as the counter only assumes odd values. In theory, this while loop is an infinite loop, but in practice,
this loop eventually terminates because of an overflow error as counter is an integer it will have a maximum
limit.
Off-By-One Bugs (OBOB): another thing for which you have to watch out in writing a loop is the so called
Off-By-One Bugs or errors. Suppose we want to execute the loop body 10 times. Does the following code
work?
E.g.:1
count = 1;
while(count < 10)
{
count++;
}
No, the loop body is executed nine times. How about the following?
E.g.:2
count = 0;
while(count <= 10)
{
…
count++;
}
No this time the loop body is executed eleven times. The correct is
E.g.:3
count = 0;
while(count < 10)
{
…
count++;
}
OR
count = 1;
while(count <= 10)
{
…
count++;
}
Page 43 of 103 BU Department of Computer Science
Fundamentals of Computer Programming
for(int n=10;n>0;n--)
{ if(n==5)
continue; //causes a jump to n—
cout<<n<< ―,‖;
}
When the continue statement appears inside nested loops, it applies to the loop immediately enclosing it,
and not to the outer loops. For example, in the following set of nested loops, the continue statement
applies to the ―for‖ loop, and not to the ―while‖ loop.
E.g.:
while(more)
{
for(i=0;i<n;i++)
{ cin>>num;
if(num<0)
continue; //causes a jump to : i++
}
}
30 31 32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47 48 49
3. A prime number is an integer greater than one and divisible only by itself and one. The first seven prime
numbers are 2, 3, 5, 7, 11, 13, and 17. Write a program that displays all the prime numbers between 1 and
100.
4. Write a C++ program that counts the number of digits in an integer number. For example; 23,498 has five
digits.
5. Write a C++ application that can compute the letter grade of a student after accepting the student‘s mid and
final mark. The program should only accept mid result [0-40] and final [0- 60]. If the data entered violates
this rule, the program should display that the user should enter the mark in the specified range. The program
is also expected to run until the user refuses to continue.
6. Write a C++ program that accepts a positive number from the user and displays the factorial of that number.
Use for loops to find the factorial of the number.
7. Write a C++ code that computes the sum of the following series.
Sum = 1! + 2! + 3! + 4! + …n!
The program should accept the number from the user.
8. Using the ASCII table numbers, write a program to print the following output, using a nested for loop. (Hint: the
outer loop should loop from 1 to 5, and the inner loop‘s start variable should be 65, the value of ASCII ―A‖).
A
AB
ABC
ABCD
ABCDE
9. Write a C++ program that displays the following output using their ASCII values.
a
bc
def
gehi
jklmn
opqrst
10. Write a C++ program that will print the following shapes.
A. B. C. D.
* ***** * *
** **** *** ***
*** *** ***** *****
**** ** ******* ***
***** * ********* *
11. Write a weather-calculator program that asks for a list of the previous 10 days‘ temperatures, computes the
average, and prints the results. You have to compute the total as the input occurs, then divide that total by 10
to find the average. Use a while loop for the 10 repetitions.
12. Write a C++ program that accepts marks of five students and then displays their average. The program
should not accept mark which is less than 0 and mark greater than 100.
13. Develop a calculator program that computes and displays the result of a single requested operation.
E.g. if the input is
15 * 20, then the program should display 15 * 20 equals 300
If the operator is not legal, as in the following example
24 ~ 25 then the program displays ~ is unrecognized operator
As a final example, if the denominator for a division is 0, as in the following input: 23 / 0 then the
program should display the following:
23 / 0 can‘t be computed: denominator is 0.
14. Use either a switch or an if-else statement and display whether a vowel or a consonant character is entered
by the user. The program should work for both lower case and upper case letters.
15. Write a C++ code to display only even numbers found between 0 and 20.
16. Write a C++ application that extracts a day, month and year and determine whether the date is valid. If the
program is given a valid date, an appropriate message is displayed. If instead the program is given an invalid
date, an explanatory message is given. Note: to recognize whether the date is valid, we must be able to
determine whether the year is a leap year or not.
An example of the expected input/output behavior for a valid date follows
Chapter Four
4. Arrays and Strings
What is An Array?
A collection of identical data objects, which are stored in consecutive memory locations under
a common heading or a variable name. In other words, an array is a group or a table of values
referred to by the same name. The individual values in array are called elements. Array
elements are also variables.
Set of values of the same type, which have a single name followed by an index. In C++,
square brackets appear around the index right after the name.
A block of memory representing a collection of many simple data variables stored in a
separate array element, and the computer stores all the elements of an array consecutively
in memory.
Properties of arrays:
Arrays in C++ are zero-bounded; that is the index of the first element in the array is 0
and the last element is N-1, where N is the size of the array.
It is illegal to refer to an element outside of the array bounds, and your program will
crash or have unexpected results, depending on the compiler.
Array can only hold values of one type.
Array declaration
Declaring the name and type of an array and setting the number of elements in an array is
called dimensioning the array. The array must be declared before one uses in like other
variables. In the array declaration one must define:
1. The type of the array (i.e. integer, floating point, char etc.)
2. Name of the array,
3. The total number of memory locations to be allocated or the maximum value of each
subscript. i.e. the number of elements in the array.
So the general syntax for the declaration is:
DataTypename arrayname [array size];
The expression array size, which is the number of elements, must be a constant such as 10 or a
symbolic constant declared before the array declaration, or a constant expression such as
10*sizeof (int), for which the values are known at the time compilation takes place.
Note: array size cannot be a variable whose value is set while the program is running.
Thus to declare an integer with size of 10 having a name of num is:
int num [10];
This means: ten consecutive two byte memory location will be reserved with the name num.
That means, we can store 10 values of type int without having to declare 10 different variables
each one with a different identifier. Instead of that, using an array we can store 10 different
values of the same type, int for example, with a unique identifier.
Initializing Arrays
When declaring an array of local scope (within a function), if we do not specify the array
variable will not be initialized, so its content is undetermined until we store some values in
it.
If we declare a global array (outside any function) its content will be initialized with all its
elements filled with zeros. Thus, if in the global scope we declare:
int day [5];
every element of day will be set initially to 0:
But additionally, when we declare an Array, we have the possibility to assign initial
values to each one of its elements using curly brackets { } . For example:
int day [5] = { 16, 2, 77, 40, 12071 };
The above declaration would have created an array like the following one:
The number of elements in the array that we initialized within curly brackets { } must be equal
or less than the length in elements that we declared for the array enclosed within square
brackets [ ]. If we have less number of items for the initialization, the rest will be filled with zero.
For example, in the example of the day array we have declared that it had 5 elements and in the
list of initial values within curly brackets { } we have set 5 different values, one for each element.
If we ignore the last initial value (12071) in the above initialization, 0 will be taken automatically
for the last array element.
Because this can be considered as useless repetition, C++ allows the possibility of leaving empty
the brackets [ ], where the number of items in the initialization bracket will be counted to set the
size of the array.
int day [] = { 1, 2, 7, 4, 12,9 };
The compiler will count the number of initialization items which is 6 and set the size of the array
day to 6 (i.e.: day[6])
You can use the initialization form only when defining the array. You cannot use it later, and
cannot assign one array to another once i.e.
int arr [] = {16, 2, 77, 40, 12071};
int ar [4];
ar[]={1,2,3,4};//not allowed
arr=ar;//not allowed
Note: when initializing an array, we can provide fewer values than the array elements. E.g.
int a [10] = {10, 2, 3}; in this case the compiler sets the remaining elements to zero.
In c++ the first element has an index of 0 and the last element has an index, which is
one less the size of the array (i.e. arraysize-1). Thus, from the above declaration, day[0]
is the first element and day[4] is the last element.
Following the previous examples where day had 5 elements and each element is of
type int, the name, which we can use to refer to each element, is the following one:
For example, to store the value 75 in the third element of the array variable day a
suitable sentence would be:
And, for example, to pass the value of the third element of the array variable day to
the variable a , we could write:
a = day[2];
Therefore, for all the effects, the expression day[2] is like any variable of type int with
the same properties. Thus an array declaration enables us to create a lot of variables of
the same type with a single declaration and we can use an index to identify individual
elements.
Notice that the third element of day is specified day[2] , since first is day[0] , second
day[1] , and therefore, third is day[2] . By this same reason, its last element is day [4].
Since if we wrote day [5], we would be acceding to the sixth element of day and
therefore exceeding the size of the array. This might give you either error or
unexpected value depending on the compiler.
In C++ it is perfectly valid to exceed the valid range of indices for an Array, which can
cause certain detectable problems, since they do not cause compilation errors but they
can cause unexpected results or serious errors during execution. The reason why this
is allowed will be seen ahead when we begin to use pointers.
At this point it is important to be able to clearly distinguish between the two uses the
square brackets [ ] have for arrays.
o One is to set the size of arrays during declaration
o The other is to specify indices for a specific array element when accessing the
elements of the array
We must take care of not confusing these two possible uses of brackets [ ] with arrays:
Eg: int day[5]; // declaration of a new Array (begins with a type name)
day[2] = 75; // access to an element of the Array.
#include <iostream.h>
int day [ ] = {16, 2, 77, 40, 12071};
int n, result=0;
void main ()
{
for ( n=0 ; n<5 ; n++ )
{ result += day[n];
}
cout << result;
getch(); }
Strings of Characters:
What are Strings?
In all programs and concepts we have seen so far, we have used only numerical variables,
used to express numbers exclusively. But in addition to numerical variables there also
exist strings of characters that allow us to represent successive characters, like words,
sentences, names, texts, etc. Until now we have only used them as constants, but we have
never considered variables able to contain them.
In C++ there is no specific elementary variable type to store string of characters. In order
to fulfill this feature we can use arrays of type char, which are successions of char
elements. Remember that this data type (char) is the one used to store a single character,
for that reason arrays of them are generally used to make strings of single characters.
For example, the following array (or string of characters) can store a string up to 20
characters long. You may imagine it thus:
char name [20];
name
This maximum size of 20 characters is not required to be always fully used. For example,
name could store at some moment in a program either the string of characters "Hello" or
the string "studying C++”. Therefore, since the array of characters can store shorter strings
than its total length, there has been reached a convention to end the valid content of a
string with a null character, whose constant can be written as '\0’.
We could represent name (an array of 20 elements of type char) storing the strings of
characters "Hello" and "Studying C++" in the following way:
H e l l 0 \0
S t u d y i n g C + + \0
Notice how after the valid content it is included a null character ('\0') in order to indicate
the end of string. The empty cells (elements) represent indeterminate values.
Initialization of Strings
Because strings of characters are ordinary arrays they fulfill same rules as any array. For
example, if we want to initialize a string of characters with predetermined values we can do it
in a similar way to any other array:
char mystring[] = { 'H', 'e', 'l', 'l', 'o', '\0' };
In this case we would have declared a string of characters (array) of 6 elements of type char
initialized with the characters that compose Hello plus a null character '\0’.
Nevertheless, string of characters have an additional way to initialize its values: using
constant strings.
In the expressions we have used in examples of previous chapters there have already
appeared several times constants that represented entire strings of characters. These are
specified enclosed between double quotes ( “ “ ), for example:
Unlike single quotes ( ' ) which allow to specify single character constants, double quotes ( " )
are constants that specify a succession of characters. These strings enclosed between double quotes
have always a null character („\0‟) automatically appended at the end.
Therefore we could initialize the string mystring with values by any of these two ways:
In both cases the Array or string of characters mystring is declared with a size of 6 characters
(elements of type char ): the 5 characters that compose Hello plus a final null character ( '\0' )
which specifies the end of the string and that, in the second case, when using double quotes (
" ) it is automatically appended.
Before going further, you should note that the assignation of multiple constants like double-
quoted constants ( " ) to arrays are only valid when initializing the array, that is, at the moment
when declared.
The following expressions within a code are not valid for arrays
mystring="Hello";
mystring[] = "Hello";
neither would be: mystring = { 'H', 'e', 'l', 'l', 'o', '\0' };
So remember: We can "assign" a multiple constant to an Array only at the moment of initializing
it. The reason will be more comprehensible when you know a bit more about pointers, since
then it will be clarified that an array is simply a constant pointer pointing to an allocated block
of memory. And because of this constant feature, the array itself cannot be assigned any
value, but we can assign values to each of the elements of the array.
At the moment of initializing an Array it is a special case, since it is not an assignation,
although the same equal sign (=) is used. Anyway, have always present the rule previously
underlined.
{
dest[c] = source[c];
c++;
}
dest[c] = „\0‟;
Page 52 of 103 BU Department of Computer Science
Fundamentals of Computer Programming
void main()
{ clrscr();
char name[10],dest[10];
cout<< “\n enter your name : ”;
cin>>name;
namecopy(dest,name);
getch();
}
Another frequently used method to assign values to an array is by using directly the input
stream (cin). In this case the value of the string is assigned by the user during program
execution.
When cin is used with strings of characters it is usually used with its getline method, that can
be called following this prototype:
cin.getline ( char buffer [], int length , char delimiter = ' \n');
where buffer is the address where to store the input (like an array, for example), length is the
maximum length of the buffer (the size of the array) and delimiter is the character used to
determine the end of the user input, which by default - if we do not include that parameter -
will be the newline character ( '\n' ).
The following example repeats whatever you type on your keyboard. It is quite simple but
serves as example on how you can use cin.getline with strings:
// cin with strings
#include <iostream.h>
#include<conio.h>
int main ()
{ char mybuffer [100];
cout << "What's your name? ";
cin.getline (mybuffer,100);
cout << "Hello " << mybuffer << ".\n";
cout << "Which is your favourite team? ";
cin.getline (mybuffer,100);
cout << "I like " << mybuffer << " too.\n";
getch();
return 0;
}
Notice how in both calls to cin.getline we used the same string identifier (mybuffer). What
the program does in the second call is simply step on the previous content of buffer by the
new one that is introduced.
If you remember the section about communication through console, you will remember that
we used the extraction operator ( >> ) to receive data directly from the standard input. This
method can also be used instead of cin.getline with strings of characters. For example, in our
program, when we requested an input from the user we could have written:
cin >> mybuffer;
this would work, but this method has the following limitations that cin.getline has not:
It can only receive single words (no complete sentences) since this method uses as delimiter any
occurrence of a blank character, including spaces, tabulators, newlines and carriage returns.
It is not allowed to specify a size for the buffer. What makes your program unstable in case that the
user input is longer than the array that will host it.
For these reasons it is recommendable that whenever you require strings of characters coming
from cin you use cin.getline instead of cin >> .
All of these functions admit one parameter and return a value of the requested type (int, long
or float). These functions combined with getline method of cin are a more reliable way to get
the user input when requesting a number than the classic cin>> method:
// cin and ato* functions
#include <iostream.h>
#include <stdlib.h>
#include<conio.h>
int main()
{ clrscr();
char mybuffer[100];
float price;
int quantity;
cout << "Enter price: ";
cin.getline (mybuffer,100);
price = atof (mybuffer);
cout << "Enter quantity: ";
cin.getline (mybuffer,100);
quantity = atoi (mybuffer);
cout<<"\nafter conversion :\n";
cout<<"\nprice is : "<<price;
cout<<"\nquantity is : "<<quantity;
cout << "\nTotal price: " << price*quantity;
getch();
return 0;
}
Page 54 of 103 BU Department of Computer Science
Fundamentals of Computer Programming
Matrix represents a bi-dimensional array of 3 per 5 values of type int . The way to declare this
array would be:
int matrix[3][5];
For example, the way to reference the second element vertically and fourth horizontally in an
expression would be:
matrix[1][3]
We have used defined constants ( #define ) to simplify possible future modifications of the
program, for example, in case that we decided to enlarge the array to a height of 4 instead of 3
it would be enough by changing the line:
#define HEIGHT 3
by the following code
Page 56 of 103 BU Department of Computer Science
Fundamentals of Computer Programming
#define HEIGHT 4
Worksheet No 4:
Chapter Five
Functions
5.1 Introduction
A function is defined as a group of instruction used to achieve a specific task. These functions can be called
from other function. Hence if any groups of statements are to be frequently used then the statements are
grouped together and named which is accessed by that new function when needed.
Functions decrease the complexity of a program. A program having multiple functions can be easily
debugged than a program that is large and runs without a single function. So a function reduces the size of a
program and increases the program modularity.
C++ adopts functions as its fundamental programming approach .Basics of C++ deals more with functions
and even classes also use the functions as their member functions.
Advantages of functions
Increase program modularity
Reduction in the amount of work & development time
Program and function debugging is easier
Division of work is simplified
Reduction in the size of the program due to code reusability
They can be accessed repeatedly without redevelopment, which in turn promotes reuse of code
5.2 Types of function
Functions are of two types:
Library/built-in function
User defined function
5.2.1 Library/Built-in function
Library functions are pre-written functions or built in functions. Many activities in C++ use library
functions. These functions include graphical functions, text formatting functions, memory management and
data conversion.
Some of the mathematical functions available in the C++ mathematics library are listed below.
acos(x) inverse cosine, -1 <= x <= +1, returns value in radians in range 0 to PI
asin(x) inverse sine, -1 <= x <= +1, returns value in radians in range 0 to PI
atan(x) inverse tangent, returns value in radians in range -PI/2 to PI/2
cos(x) returns cosine of x, x in radians
sin(x) returns sine of x, x in radians
exp(x) exponential function, e to power x
log(x) natural log of x (base e), x > 0
sqrt(x) square root of x, x >= 0
fabs(x) absolute value of x
pow(x,y) x the power of y
floor(x) largest integer not greater than x
ceil(x) smallest integer not less than x
Consider the following example which uses ceil and floor library functions from math.h. The floor function
rounds up the float value to the nearest lower integer where as ceil rounds up the float value to the nearest
upper integer.
Output
Example:
#include<math.h>
#include<iostream.h>
int main()
{
float number=255.98;
float down,up;
down=floor(number);
up=ceil(number);
cout<<‖The number is ―<<number<<endl;
cout<<‖The floor of the number is‖<<down<<endl;
cout<<‖The ceil part of the number is‖<<up<<endl;
return 0;
}
5.2.2 User defined functions
Besides the library functions, we can also define our own functions which are called as user defined
functions. C++ allows declaring user-defined functions, which reduces program size and increase
modularity.
The following program shows how to use user-defined functions. Example:
#include<iostream.h>
Output
void func();//Function declaration
void main()
{
func();//Function calling
cout<<‖Statement 1 in main function‖<<endl;
func();//Function calling
cout<<‖Statement 2 in main function‖<<endl;
func();//function can be called from main any number of times
}
void func()
{
cout<‖Function called from main‖<<endl;//function definition
}
Just like a variable has to be declared before using, a function also has to be declared.
The statement just above the main is the function declaration. A function declaration tells the compiler
that at some later point we are going to use a function by that name. It is called as prototype declaration. It
should be terminated because it acts like a single statement.
}
Return type is void
void func1() no semicolon. Decelerator
{
-------------- function body definition
--------------
} no semicolon.
Function Return
Functions can be grouped into two categories: function that do not have a return value (void function
and functions that have a return value)
The return statement in a function need not at the end of the function. It can occur anywhere in the
function body and as soon as it as countered, execution control will be returned to the caller.
Caller called
A function can also have arguments. An argument is a piece of data passed from a program to a function.
The arguments are the variables that are passed in the parenthesis of a function. These arguments are used
to process the data sent by the program.
Syntax:
void myfunc(int,int);
This specifies the function called myfunc that takes two integer variables as arguments. A compiler
identifies a function with the number of arguments and type of arguments other-wise which raises a
compiler error. When we are declaring functions, the variables in function declaration are known as
parameters. During function execution they are known as function arguments.
Example:
#include<iostream.h>
void main()
{
Output
int x,y;//declares two integer variables
Page 62 of 103 BU Department of Computer Science
Fundamentals of Computer Programming
cin>>x;
cin>>y;
Sometimes it becomes necessary that a program passing arguments expecting a return from the function.
This is known as arguments with return value. Actually when you declare a function as void it implies that
the function need not return anything.
This means that if you don’t specify void before the function name, the calling function is expecting a
return from the called function.
The return may be an int variable or a char variable or any other variable of any type. In this case a function
that returns a value should be specified before the function at the time of declaration and definition.
Example:
The program defines a function called power, which takes two integer variables and prints the power of the
first number raised to second number. Finally after calculating power the value is returned to the calling
function. You will observe that in place of void before the function name it is given as int so that it will
return a value of int.
#include<iostream.h>
int power(int,int);//function declaration with return value
void main()
{
int a,b,c;
cout<<‖Enter the first number‖<<endl;
cin>>a;
cout<<‖Enter the second number‖<<endl;
cin>>b;
c=power(a,b);//assigning the returned value of the function power
cout<<‖The result of ‖<<a<<‖ raised ‖<<b<<‖ is: ‖<<c;
}//definition of function power
Output
int power(int i,int j)
{
int p=1;
while(j>0)
{
p=p*i;
j--;
}
return p;//p is returned to initialize to c
}
From the above program it is understood that, to make a function to return a value, the type has to be
specified before the function name.
being passed to the function to the caller function. And hence the alteration for the original variables is
possible.
Example:
The program follows call by reference method to swap two variables.
#include<iostream.h>
int swap(int &,int &);//& indicates you are passing the addresses of the values not the values
void main()
{
int a=10;
int b=90;
swap(a,b);//values of a and b are passed to the function
cout<<‖The values of a is:‖<<a<<endl;
cout<<‖The value of b is: <<b<<endl; Output
The value of a is: 90
}
int swap(int &p,int &q) The value of b is: 10
{
int temp;
temp=p;
p=q;
q=temp;
return 0;
}
In the example shown above you passed the address of the variables as argument. You will find that the
declaration of swap included an & specified in place of arguments. It means that the function is expecting
addresses of the variables as arguments.
& is called “address of” operator. It is used to pass the address of a variable to the called function or
variable. So the variable declared in definition of function also gets created at the same address. It implies
that the variables can access the value of original variables. Thus they can be altered. So call by reference
works fine when it is needed to access the original variables not created a copy of it.
Arrays as parameters
At some moment we may need to pass an array to a function as a parameter. In C++ it is not possible to
pass by value a complete block of memory as a parameter, even if it is ordered as an array, to a
function, but it is allowed to pass its address, which has almost the same practical effect and is a much
faster and more efficient operation.
In order to admit arrays as parameters the only thing that we must do when declaring the function is to
specify in the argument the base type for the array that it contains, an identifier and a pair of void
brackets [] . For example, the following function:
admits a parameter of type "Array of int " called arg . In order to pass to this function an array declared
as:
procedure (myarray);
Scope Operator
Because a local scope overrides the global scope, having a local variable with the same name as a global variable
makes the latter inaccessible to the local scope.
Eg
int num1;
void fun1(int num1)
{
//…
}
The global num1 is inaccessible inside fun1(), because it is overridden by the local num1 parameter.
This problem is overcome using the scope operator ‗::‘ which takes a global entity as argument.
int num1 = 2;
void fun1(int num1)
{
//…
num1=33;
cout<<num1; // the output will be 33
cout<<::num1; //the output will be 2 which is the global
if(::num1 != 0)//refers to global num1
//…
float fabs(float x)
{ if(x<0.0)
return (x * -1.0);
else
return (x);
}
Without using overloading, you have to call the function as:
int ans = iabs(weight);//for int arguments
float ans = fabs(weight);//for float arguments
But with overloading, the above code can be used as:
N.B: if two or more functions differ only in their return types, C++ can‘t overload them. Two or
more functions that differ only in their return types must have different names and can‘t be
overloaded
5.6. Recursion
A function which calls itself is said to be recursive. Recursion is a general programming
technique applicable to problems which can be defined in terms of them selves. Take the
factorial problem, for instance which is defined as:
- factorial of 0 is 1
- factorial of a positive number n is n time the factorial of n-1.
The second line clearly indicates that factorial is defined in terms of itself and hence can be
expressed as a recursive function.
int Factorial(unsigned int n )
{
return n = = 0 ? 1 : n * factrial(n-1);
}
For n set to 4, the following figure shows the recursive call:
Factorial(4)
24
4 * Factorial(3)
6 3 * Factorial(2)
2 2* Factorial(1)
1 1
The stack frames for these calls appear sequentially on the runtime stack, one after the other.
A recursive function must have at least one termination condition which can be satisfied.
Otherwise, the function will call itself indefinitely until the runtime stack overflows.
Chapter Six
6. Pointers
We have already seen how variables are memory cells that we can access by an identifier. But
these variables are stored in concrete places of the computer memory. For our programs, the
computer memory is only a succession of 1 byte cells (the minimum size for a datum), each one
with a unique address.
A pointer is a variable which stores the address of another variable. The only difference
between pointer variable and regular variable is the data they hold.
There are two pointer operators in C++:
& the address of operator
* the dereference operator
Whenever you see the & used with pointers, think of the words ―address of.‖ The & operator
always produces the memory address of whatever it precedes. The * operator, when used with
pointers, either declares a pointer or dereferences the pointer‘s value. The dereference operator
can be literally translated to "value pointed by”.
A pointer is simply the address of an object in memory. Generally, objects can be accessed in
two ways: directly by their symbolic name, or indirectly through a pointer. The act of getting to
an object via a pointer to it is called dereferencing the pointer. Pointer variables are defined to
point to objects of a specific type so that when the pointer is dereferenced, a typed object is
obtained.
At the moment in which we declare a variable this one must be stored in a concrete location in
this succession of cells (the memory). We generally do not decide where the variable is to be
placed - fortunately that is something automatically done by the compiler and the operating
system on runtime, but once the operating system has assigned an address there are some cases
in which we may be interested in knowing where the variable is stored.
This can be done by preceding the variable identifier by an ampersand sign (&), which literally
means, "address of”. For example:
ptr= &var;
This would assign to variable ptr the address of variable var , since when preceding the name
of the variable var with the ampersand ( & ) character we are no longer talking about the
content of the variable, but about its address in memory.
We are going to suppose that var has been placed in the memory address 1776 and that we
write the following:
var=25;
x=var;
ptr = &var;
The result will be the one shown in the following diagram:
We have assigned to x the content of variable var as we have done in many other occasions in
previous sections, but to ptr we have assigned the address in memory where the operating
system stores the value of var , that we have imagined that it was 1776 (it can be any address).
The reason is that in the allocation of ptr we have preceded var with an ampersand ( & )
character.
The variable that stores the address of another variable (like ptr in the previous example) is
what we call a pointer.
Declaring Pointers:
Is reserving a memory location for a pointer variable in the heap.
Syntax:
type * pointer_name ;
to declare a pointer variable called p_age, do the following:
int * p_age;
Whenever the dereference operator, *, appears in a variable declaration, the variable being
declared is always a pointer variable.
cout<<*p_age;//dereferences p_age;
The dereference operator produces a value that tells the pointer where to point. Without the *,
(i.e cout<<p_age), a cout statement would print an address (the address of age). With the *, the
cout prints the value at that address.
You can assign a different value to age with the following statement:
age = 13; //assigns a new value to variable age
*p_age = 13 //assigns 13 as a value to the memory p_age points at.
N.B: the * appears before a pointer variable in only two places: when you declare a pointer
variable and when you dereference a pointer variable (to find the data it points to).
- The following program is one you should study closely. It shows more about pointers and
the pointer operators, & and *, than several pages of text could do.
#...
#...
int main()
{
int num = 123; // a regular integer variable
int *p_num; //declares an integer pointer
cout<< “num is ”<<num<<endl;
cout<< “the address of num is ”<<&num<<endl;
p_num = #// puts address of num in p_num;
cout<< “*p_num is ”<<*p_num<<endl; //prints value of num
cout<< “p_num is ”<<p_num<<endl; //prints value of P_num
Pointer to void
Note that we can‘t assign the address of a float type variable to an integer pointer variable and
similarly the address of an integer variable can not be stored in a float or character pointer.
flaot y;
int x;
int *ip;
float *fp;
ip = &y; //illegal statement
fp = &x; //illegal statement
That means, if a variable type and pointer to type is same, then only we can assign the address
of variable to pointer variable. And if both are different type then we can‘t assign the address of
variable to pointer variable but this is also possible in C++ by declaring pointer variable as a
void as follows:
void *p;
int x;
float y;
The difficulty on void pointers is that, void pointers can not be de referenced. They are aimed
only to store address and the dereference operator is not allowed for void pointers.
Arrays of Pointers
If you have to reserve many pointers for many different values, you might want to declare an
array of pointers.
Page 73 of 103 BU Department of Computer Science
Computer Programming
At this point p and numbers are equivalent and they have the same properties, with the only
difference that we could assign another value to the pointer p whereas numbers will always
point to the first of the 20 integer numbers of type int with which it was defined. So, unlike p,
that is an ordinary variable pointer, numbers is a constant pointer (indeed that is an Array: a
constant pointer). Therefore, although the previous expression was valid, the following
allocation is not:
numbers = p;
Because numbers is an array (constant pointer), and no values can be assigned to constant
identifiers.
N.B: An array name is just a pointer, nothing more. The array name always points to the first
element stored in the array. Therefore , we can have the following valid C++ code:
int ara[5] = {10,20,30,40,50};
cout<< *(ara + 2); //prints ara[2];
The expression *(ara+2) is not vague at all if you remember that an array name is just a pointer
that always points to the array‘s first element. *(ara+2) takes the address stored in ara, adds 2 to
the address, and dereferences that location.
Consider the following character array:
char name[] = ―C++ Programming‖;
What output do the following cout statements produce?
cout<<name[0]; // ___C__
Page 74 of 103 BU Department of Computer Science
Computer Programming
cout<<*name; // ___C__
cout<<*(name+3); //_________
cout<<*(name+0); //____C____
Pointer Advantage
You can‘t change the value of an array name, because you can‘t change constants. This explains
why you can‘t assign an array a new value during a program‘s execution: eg: if Cname is array
of characters then:
Cname = “Football”; //invalid array assignment;
Unlike arrays, you can change a pointer variable. By changing pointers, you can make them
point to different values in memory. Have a look at the following code:
#...
#...
int main()
{
float v1 = 679.54;
float v2 = 900.18;
float * p_v;
p_v = &v1;
cout<< “\n the first value is ”<<*p_v;//print the value of v1;
p_v = &v2;
cout<< “\n the second value is ”<<*p_v; m//print the value of v2;
}
You can use pointer notation and reference pointers as arrays with array notation. Study the
following program carefully. It shows the inner workings of arrays and pointer notation.
int main()
{
int ctr;
int iara[5] = {10,20,30,40,50};
int *iptr;
iptr = iara; //makes iprt point to array’s first element. Or iprt = &iara[0]
cout<< “using array subscripts:\n”
cout<< “iara\tiptr\n”;
for(ctr=0;ctr<5;ctr++)
cout<<iara[ctr]<< “\t”<< iptr[ctr]<< “\n”;
cout<< “\nUsing pointer notation\n”;
for(ctr=0;ctr<5;ctr++)
cout<< *(iara+ctr) << “\t” << *(iptr+ctr)<< “\n”;
}
Suppose that you want to store a persons name and print it. Rather than using arrays, you can
use a character pointer. The following program does just that.
int main()
{
char *c = “Meseret Belete”;
cout<< “your name is : ”<<c;
}
Suppose that you must change a string pointed to by a character pointer, if the persons name in
the above code is changed to Meseter Alemu: look at the following code:
int main()
{
char *c = “Meseret Belete”;
cout<< “youe name is : ”<<c;
c = “Meseret Alemu”;
cout<< “\nnew person name is : ”<<c;
}
If c were a character array, you could never assign it directly because an array name can‘t be
changed.
Pointer Arithmetic
To conduct arithmetical operations on pointers is a little different than to conduct them on other
integer data types. To begin, only addition and subtraction operations are allowed to be
conducted, the others make no sense in the world of pointers. But both addition and subtraction
have a different behavior with pointers according to the size of the data type to which they point
to.
When we saw the different data types that exist, we saw that some occupy more or less space
than others in the memory. For example, in the case of integer numbers, char occupies 1 byte,
short occupies 2 bytes and long occupies 4.
And that we know that they point to memory locations 1000 , 2000 and 3000 respectively. So if
we write:
mychar++;
myshort++;
mylong++;
mychar , as you may expect, would contain the value 1001 . Nevertheless, myshort would
contain the value 2002 , and mylong would contain 3004 . The reason is that when adding 1 to a
pointer we are making it to point to the following element of the same type with which it has
been defined, and therefore the size in bytes of the type pointed is added to the pointer.
This is applicable both when adding and subtracting any number to a pointer.
It is important to warn you that both increase ( ++ ) and decrease ( -- ) operators have a greater
priority than the reference operator asterisk ( * ), therefore the following expressions may lead
to confusion:
*p++;
*p++ = *q++;
The first one is equivalent to *(p++) and what it does is to increase p (the address where it
points to - not the value that contains).
The second, because both increase operators (++) are after the expressions to be evaluated and
not before, first the value of *q is assigned to *p and then they are both q and p increased by
one. It is equivalent to:
*p = *q;
p++;
q++;
Now let us have a look at a code that shows increments through an integer array:
int main()
{
int iara[] = {10,20,30,40,50};
int * ip = iara;
cout<<*ip<<endl;
ip++;
cout<<*ip<<endl;
ip++;
cout<<*ip<<endl;
ip++;
cout<<*ip<<endl;
}
G e o r g e \0
M e s f i n \0
J o h n \0
K i m \0
B a r b a r a \0
Notice that much of the table is waster space. Each row takes 20 characters, even though the
data in each row takes far fewer characters.
To fix the memory-wasting problem of fully justified tables, you should declare a single-
dimensional array of character pointers. Each pointer points to a string in memory and the
strings do not have to be the same length.
Here is the definition for such an array:
char *name [5] = {{“George”},{“Mesfin”},{“John”}, {“Kim”},{“Barbara”}};
This array is a single-dimension array. The asterisk before names makes this array an array of
pointers. Each string takes only as much memory as is needed by the string and its terminating
zero. At this time, we will have this structure in memory:
To print the first string, we should use:
cout<<*names; //prints George.
To print the second use:
cout<< *(names+1); //prints Mesfin
Whenever you dereference any pointer element with the * dereferencing operator, you access
one of the strings in the array.
Pointer to pointer:
As the memory address where integer, float or character is stored in can be stored into a pointer
variable, the address of a pointer can also be stored in another pointer. This pointer is said to be
pointer to a pointer.
An array of pointer is conceptually same as pointer to pointer type. The pointer to pointer type
is declared as follows:
Data_type ** pointer_name;
Note that the asterisk is double here.
int **p; //p is a pointer which holds the address another pointer.
E.g.:
char a;
char * b;
char ** c;
a = 'z';
b = &a;
c = &b;
This, supposing the randomly chosen memory locations of 7230 , 8092 and 10502 , could be
described thus:
(inside the cells there is the content of the variable; under the cells its location)
Have a look at the following code:
#...
Page 78 of 103 BU Department of Computer Science
Computer Programming
int main()
{ int data;
int *p1;
int **p2;
data = 15;
cout<< “data = ”<<data<<endl;
p1 = &data;
p2 = &p1;
cout<< “data through p1 = ”<<*p1<<endl;//print the value of data;
cout<< “data through p2 = ”<< **p2<<endl; //print the value of data;
}
Dynamic memory:
Until now, in our programs, we have only had as much memory as we have requested in
declarations of variables, arrays and other objects that we included, having the size of all of
them to be fixed before the execution of the program. But, What if we need a variable amount
of memory that can only be determined during the program execution (runtime)? For example,
in case that we need a user input to determine the necessary amount of space. The answer is
dynamic memory, for which C++ integrates the operators new and delete.
Pointers are useful for creating dynamic objects during program execution. Unlike normal
(global and local) objects which are allocated storage on the runtime stack, a dynamic object is
allocated memory from a different storage area called the heap. Dynamic objects do not obey
the normal scope rules. Their scope is explicitly controlled by the programmer.
a) The New Operator
In C++ new operator can create space dynamically i.e at run time, and similarly delete
operator is also available which releases the memory taken by a variable and return
memory to the operating system.
When the space is created for a variable at compile time this approach is called static. If
space is created at run time for a variable, this approach is called dynamic. See the
following two lines:
int a[10];//creation of static array
int *a;
a = new int[10];//creation of dynamic array
Lets have another example:
int * ptr3;
ptr3 = new int [5];
In this case, the operating system has assigned space for 5 elements of type int in the
heap and it has returned a pointer to its beginning that has been assigned to ptr3 .
Therefore, now, ptr3 points to a valid block of memory with space for 5 int elements.
You could ask what is the difference between declaring a normal array and assigning
memory to a pointer as we have just done. The most important one is that the size of an
array must be a constant value, which limits its size to what we decide at the moment of
designing the program before its execution, whereas the dynamic memory allocation
allows assigning memory during the execution of the program using any variable,
constant or combination of both as size.
The dynamic memory is generally managed by the operating system, and in the multi-
task interfaces can be shared between several applications, so there is a possibility that
the memory exhausts. If this happens and the operating system cannot assign the
memory that we request with the operator new, a null pointer will be returned. For that
reason it is recommendable to always verify if after a call to instruction new the returned
pointer is null:
int * ptr3;
ptr3 = new int [5];
if (ptr3 == NULL) {
// error assigning memory. Take measures.
}
if ptr3 is NULL, it means that there is no enough memory location in the heap to be
given for ptr3.
b) Operator delete
Since the necessity of dynamic memory is usually limited to concrete moments within a
program, once this one is no longer needed it shall be freed so that it become available
for future requests of dynamic memory. For this exists the operator delete , whose form
is:
delete pointer ;
or
delete [] pointer ;
The first expression should be used to delete memory allocated for a single element, and
the second one for memory allocated for multiple elements (arrays).
In most compilers both expressions are equivalent and can be used without distinction,
although indeed they are two different operators and so must be considered for operator
overloading.
In the following simple example, a program that memorizes numbers, does not have a
limited amount of numbers that can be introduced, thanks to the concept and power of
pointer that we request to the system as much space as it is necessary to store all the
numbers that the user wishes to introduce.
#include <iostream.h>
#include <stdlib.h>
int main ()
{
char input [100];
int i,n;
long * num;// total = 0;
cout << "How many numbers do you want to type in? ";
cin.getline (input,100);
Page 80 of 103 BU Department of Computer Science
Computer Programming
i=atoi (input);
num= new long[i];
if (num == NULL)
{
cout<<"\nno enough memory!";
exit (1);
}
for (n=0; n<i; n++)
{
cout << "Enter number: ";
cin.getline (input,100);
num[n]=atol (input);
}
cout << "You have entered: ";
for (n=0; n<i; n++)
cout << num[n] << ", ";
delete[] num;
}
NULL is a constant value defined in C++ libraries specially designed to indicate null
pointers. In case that this constant is not defined you can do it yourself by defining it to
0:
Chapter Seven
Structures
What is a Structure?
Structure is a collection of variables under a single name. Variables can be of any type: int, float,
char etc. The main difference between structure and array is that arrays are collections of the same
data type and structure is a collection of variables under a single name.
Declaring a Structure:
The structure is declared by using the keyword struct followed by structure name, also called a tag.
Then the structure members (variables) are defined with their type and variable names inside the
open and close braces { and }. Finally, the closed braces end with a semicolon denoted as ;
following the statement. The above structure declaration is also called a Structure Specifier.
Example:
Three variables: custnum of type int, salary of type int, commission of type float are structure
members and the structure name is Customer. This structure is declared as follows:
In the above example, it is seen that variables of different types such as int and float are grouped in
a single structure name Customer.
Arrays behave in the same way, declaring structures does not mean that memory is allocated.
Structure declaration gives a skeleton or template for the structure.
After declaring the structure, the next step is to define a structure variable.
#include<iostream.h> #include<iostream.h>
struct customer struct customer
{ {
int custnum; int custnum;
char name[10]; char name[10];
int phonenum; int phonenum;
}cust1,cust2,cust3;//structure variable declaration };
int main() int main()
{ {
…. struct customer cust1,cust2,cust3; //structure variable
} declaration
}
What happens when this is defined? When structure is defined, it allocates or reserves space in
memory. The memory space allocated will be cumulative of all defined structure members. In the
above example, there are 3 structure members: custnum, name and phonenum. Of these, two are of
type in and one is of type char. If integer space allocated by a system is 2 bytes and char one bytes
the above would allocate 2bytes for custnum, 2 bytes for phonenum and 1byte for name.
A better approach to initializing structures is to use the dot operator (.). The dot operator is one
way to initialize individual members of a structure variable in the body of your program. With
the dot operator, you can treat each structure member almost as if it were a regular non structure
variable.
The General syntax to access members of a structure variable would be:
structurevariablename.membername
A structure variable name must always precede the dot opera- tor, and a member name must
always appear after the dot operator. Using the dot operator is easy, as the following examples
show.
For example:
A programmer wants to assign 2000 for the structure member salary in the above example of
structure Customer with structure variable cust1 this is written as:
#include<iostream.h> #include<iostream.h>
struct customer struct customer
{ {
int custnum; int custnum;
char name[10]; char name[10];
int phonenum; int phonenum;
}cust1; };
int main() int main()
{ {
cout<<‖Enter customer number‖<<endl; struct customer cust1;
cin>>cust1.custnum; cout<<‖Enter customer number‖<<endl;
cout<<‖Enter customer name‖<<endl; cin>>cust1.custnum;
cin>>cust1.name; cout<<‖Enter customer name‖<<endl;
cout<<‖Enter customer phone number‖<<endl; cin>>cust1.name;
cin>>cust1.phonenum; cout<<‖Enter customer phone number‖<<endl;
cout<<‖Customer Number:‖<<cust1.custnum; cin>>cust1.phonenum;
cout<<‖\nCustomer Name:‖<<cust1.name; cout<<‖Customer Number:‖<<cust1.custnum;
cout<<‖\nCustomer Phone:‖<<cust1.phonenum; cout<<‖\nCustomer Name:‖<<cust1.name;
} cout<<‖\nCustomer Phone:‖<<cust1.phonenum;
}
Initializing structure members
You cannot initialize individual members because they are not variables. You can assign only
values to variables. The only structure variable in the above structure is cust1. The braces must
enclose the data you initialize in the structure variables, just as they enclose data when you initialize
arrays.
This method of initializing structure variables becomes tedious when there are several structure
variables (as there usually are). Putting the data in several variables, each set of data enclosed in
braces, becomes messy and takes too much space in your code.
You can initialize members when you declare a structure, or you can initialize a structure in the
body of the program.
For example
Initializing members at declaration Initializing members at the body of the program
#include<iostream.h> #include<iostream.h>
struct employee #include<string.h>
{ struct employee
char Emp_id[7]; { char Emp_id[7];
char Name[20]; char Name[20];
float Salary; float Salary;
}emp1={“DMU/001”,”Solomon”,2808}; }emp1;
int main() int main()
{ {
cout<<‖Your id:‖<<emp1.Emp_id<<endl; strcpy(emp1.Emp_id,”DMU/001/”);
cout<<‖Your name:‖<<emp1.Name<<endl; strcpy(emp1.Name,”Solomon”);
cout<<‖Your salay:‖<<emp1.Salary<<endl; emp1.Salary=2808;
} cout<<‖Your id:‖<<emp1.Emp_id<<endl;
cout<<‖Your name:‖<<emp1.Name<<endl;
cout<<‖Your salay:‖<<emp1.Salary<<endl;
}
Arrays of Structures
Arrays of structures are good for storing a complete employee file, inventory file, or any other
set of data that fits in the structure format.
Consider the following structure declaration:
struct Company
{
int employees;
int registers;
double sales;
}store[1000];
In one quick declaration, this code creates 1,000 store structures with the definition of the
Company structure, each one containing three members.
NB. Be sure that your computer does not run out of memory when you create a large number of
structures. Arrays of structures quickly consume valuable information.
You can also define the array of structures after the declaration of the structure.
struct Company
int employees;
int registers;
double sales;
#include<iostream.h>
void main()
struct Company store[1000]; //the variable store is array of the structure Company
…
}
struct student
int id;
float mark;
char name[15];
}stud[2];
int main()
for(int i=0;i<=1;i++)
cin>>stud[i].id>>stud[i].name>>stud[i].mark;
for(int i=0;i<=1;i++)
Chapter Eight
8. Streams and External Files
Introduction
- The data created by the user and assigned to variables with an assignment statement is
sufficient for some applications. With large volume of data most real-world applications
use a better way of storing that data. For this, disk files offer the solution.
- When working with disk files, C++ does not have to access much RAM because C++ reads
data from your disk drive and processes the data only parts at a time.
8.2 Stream
- Stream is a general name given to flow of data. In C++, there are different types of streams.
Each stream is associated with a particular class, which contains member function and
definition for dealing with file. Lets have a look at the figure:
ios
istream ostream
iostream
ifstream ofstream
fstream
- According to the above hierarchy, the class iostream is derived from the two classes‟
istream and ostream and both istream and ostream are derived from ios. Similarly the class
fstream is derived from iostream. Generally two main header files are used iostream.h and
fstream.h. The classes used for input and output to the video display and key board are
declared in the header file iostream.h and the classes used for disk file input output are
declared in fstream.h.
- Note that when we include the header file fstream.h in our program then there is no need
to include iostream.h header file. Because all the classes which are in fstream.h they are
derived from classes which are in iostream.h therefore, we can use all the functions of
iostream class.
- First we will see how files are opened and closed. A file can be defined by following class
ifstream, ofstream, fstream, all these are defined in fstream.h header file.
if a file object is declared by ifstream class, then that object can be used for
reading from a file.
if a file object is declared by ofstream class, then that object can be used for
writing onto a file.
If a file object is declared by fstream class then, that object can be used for both
reading from and writing to a file
8.4: Types of Disk File Access
- Your program can access files either in sequential manner or random manner. The access
mode of a file determines how one can read, write, change, add and delete data from a file.
- A sequential file has to be accessed in the same order as the file was written. This is
analogues to cassette tapes: you play music in the same order as it was recorded.
- Unlike the sequential files, you can have random-access to files in any order you want.
Think of data in a random-access file as being similar to songs on compact disc (CD): you
can go directly to any song you want to play without having to play or fast-forward
through the other songs.
8.4.1: Sequential File Concepts
- You can perform three operations on sequential disk files. You can create disk files, add to
disk files, and read from disk files.
8.4.1.1: Opening and Closing Sequential Files
- When you open a disk file, you only have to inform C++, the file name and what you want
to do with it. C++ and your operating system work together to make sure that the disk is
ready, and they create an entry in your file directory for the filename (if you are creating a
file). When you close a file, C++ writes any remaining data to the file, releases the file from
the program, and updates the file directory to reflect the file‟s new size.
- You can use either of the two methods to open a file in C++:
using a Constructor or
using the open function
- The following C++ statement will create an object with the name fout of ofstream class and
this object will be associated with file name “hello.txt”.
ofstream fout (“hello.txt”);
fout.open(“hello.txt”);
- If you open a file for writing (out access mode), C++ creates the file. If a file by that name
already exists, C++ overwrite the old file with no warning. You must be careful when
opening files not to overwrite existing data that you want.
- If an error occurs during opening of a file, C++ does not create a valid file pointer (file
object). Instead, C++ creates a file pointer (object) equal to zero. For example if you open a
file for output, but use an invalid disk name, C++ can‟t open the file and therefore makes
the file object equal to zero.
- You can also determine the file access mode when creating a file in C++. If you want to use
the open function to open a file then the syntax is:
fileobject.open(filename,accessmode);
File name is a string containing a valid file name for your computer.
Accessmode is the sought operation to be taken on the file and must be one of the
values in the following table.
Mode Description
app Opens file for appending
ate Seeks to the end of file while opening the file
in Opens the file for reading
out Opens the file for writing
binary Opens the file in binary mode
- You should always check for the successful opening of a file before starting file
manipulation on it. You use the fail() function to do the task:
- Lets have an example here:
ifstream indata;
indata.open(“c:\\myfile.txt”,ios::in);
if(indata.fail())
- In this case, the open operation will fail (i.e the fail function will return true), if there is no
file named myfile.txt in the directory C:\
- After you are done with your file manipulations, you should use the close function to
release any resources that were consumed by the file operation. Here is an example
indata.close();
- The above close() statement will terminate the relationship between the ifstream object
indata and the file name “c:\myfile.txt”, hence releasing any resource needed by the
system.
if(fp.fail())
getch();
exit(1);
fp.close();
}//end main
- A character can be written onto a file using the put() function. See the following code:
#include<fstream.h>
void main()
char c;
ofstream outfile;
outfile.open(“c:\\test.txt”,ios::out);
if(outfile.fail())
getch();
exit(1);
for(int i=1;i<=15;i++)
cin>>c;
outfile.put(c);
output.close();
}//end main
#include<stdlib.h>
void main()
ofstream outdata;
outdata.open(“c:\\names.txt”,ios::app);
if(outdata.fail())
getch();
exit(1);
outdata.close();
}//end main
- If the file names.txt does not exist, C++ creates it and stores the three names to the file.
- Basically, you have to change only the open() function‟s access mode to turn a file-creation
program into a file-appending program.
8.4.1.3: Reading from a File
- Files you open for read access (using ios::in) must exist already, or C++ gives you an error
message. You can‟t read a file that does not exist. Open() returns zero if the file does not
exist when you open it for read access.
- Another event happens when you read files. Eventually, you read all the data.
Subsequently reading produces error because there is no more data to read. C++ provides a
solution to the end-of-file occurrence.
- If you attempt to read a file that you have completely read the data from, C++ returns the
value zero. To find the end-of-file condition, be sure to check for zero when reading
information from files.
- The following code asks the user for a file name and displays the content of the file to the
screen.
#include<fstream.h>
#include<conio.h>
#include<stdlib.h>
void main()
{
clrscr();
char name[20],filename[15];
ifstream indata;
cout<<"\nEnter the file name : ";
cin.getline(filename,15);
indata.open(filename,ios::in);
if(indata.fail())
{
getch();
exit(1);
}
getch();
- You can read a characters from a file using get() function. The following program asks for a
file name and displays each character of the file to the screen. NB. A space among characters
is considered as a character and hence, the exact replica of the file will be shown in the
screen.
#include<fstream.h>
#include<conio.h>
#include<stdlib.h>
void main()
char c,filename[15];
ifstream indata;
cin.getline(filename,15);
indata.open(filename,ios::in);
getch();
exit(1);
{
indata.get(c);
cout<<c;
}
indata.close();
getch();
- Each file has two pointers one is called input pointer and second is output pointer. The input
pointer is called get pointer and the output pointer is called put pointer.
- When input and output operation take places, the appropriate pointer is automatically set
according to the access mode.
- For example when we open a file in reading mode, file pointer is automatically set to the
start of the file.
- When we open a file in append mode, the file pointer is automatically set to the end of file.
- In C++ there are some manipulators by which we can control the movement of the pointer.
The available manipulators are:
1. seekg()
2. seekp()
3. tellg()
4. tellp()
1. seekg(): this moves get pointer i.e input pointer to a specified location.
For eg. infile.seekg(5); move the file pointer to the byte number 5 from starting
point.
2. seekp(): this move put pointer (output pointer) to a specified location for example:
outfile.seekp(5);
3. tellg(): this gives the current position of get pointer (input pointer)
4. tellp(): this gives the current position of put pointer (output pointer)
eg. ofstream fileout;
fileout.open(“c:\\test.txt”,ios::app);
- By the above statement in length, the total number bytes of the file are assigned to the
integer variable length. Because the file is opened in append mode that means, the file
pointer is the last part of the file.
- Now lets see the seekg() function in action
#include<fstream.h>
#include<conio.h>
#include<stdlib.h>
void main()
clrscr();
fstream fileobj;
fileobj.open("c:\\alph.txt",ios::out|ios::in);
if(fileobj.fail())
getch();
exit(1);
{
Page 95 of 103 BU Department of Computer Science
Computer Programming
fileobj<<ch;
fileobj>>ch;
fileobj>>ch;
fileobj.close();
getch();
- To point to the end of a data file, you can use the seekg() function to position the file
pointer at the last byte. This statement positions the file pointer to the last byte in the file.
Fileobj.seekg(0L,ios::end);
- This seekg() function literally reads “move the file pointer 0 bytes from the end of the file.”
The file pointer now points to the end-of-file marker, but you can seekg() backwards to find
other data in the file.
- The following program is supposed to read “c:\alph.txt” file backwards, printing each
character as it skips back in the file.
- Be sure that the seekg() in the program seeks two bytes backwards from the current
position, not from the beginning or the end as the previous programs. The for loop towards
the end of the program needs to perform a “skip-two-bytes-back”, read-one-byte-forward”
method to skip through the file backwards.
#include<fstream.h>
#include<conio.h>
#include<stdlib.h>
void main()
clrscr();
ifstream indata;
int ctr=0;
char inchar;
indata.open("c:\\alph.txt",ios::in);
if(indata.fail())
getch();
exit(1);
for(ctr=0;ctr<26;ctr++)
indata>>inchar;
indata.seekg(-2L,ios::cur);
cout<<inchar;
indata.close();
getch();
- The default access mode for file access is text mode. A text file is an ASCII file, compatible
with most other programming languages and applications. Programs that read ASCII files
can read data you create as C++ text files.
- If you specify binary access, C++ creates or reads the file in binary format. Binary data files
are “squeezed”- that is, they take less space than text files. The disadvantage of using binary
files is that other programs can‟t always read the data files. Only C++ programs written to
access binary files can read and write them. The advantage of binary files is that you save
disk space because your data files are more compact.
- The binary format is a system-specific file format. In other words, not all computers can read
a binary file created on another computer.
8.4.2: Random Access File Concepts
- Random access enables you to read or write any data in your disk file with out having to
read and write every piece of data that precedes it.
- Generally you read and write file records. A record to a file is analogues to a C++ structure.
A record is a collection of one or more data values (called fields) that you read and write to
disk. Generally you store data in the structures and write structures to disk.
- When you read a record from disk, you generally read that record into a structure variable
and process it with your program.
- Most random access files are fixed-length records. Each record (a row in the file) takes the
same amount of disk space.
- With fixed length records, your computer can better calculate where on the disk the desired
record is located.
0 100 200 300 400 500
Byte
offsets
- There is really no difference between sequential files and random files in C++. The
difference between the files is not physical, but lies in the method that you use to access
them and update them.
- The ostream member function write outputs a fixed number of bytes, beginning at a
specific location in memory, to the specified stream.
- When the stream is associated with a file, function write writes the data at the location in
specified by the “put” file position pointer.
- The istream member function read inputs a fixed number of bytes from the specified
stream into an area in memory beginning at the specified address.
- When the stream is associated with a file, function read inputs bytes at the location in the
file specified by the “get” file poison pointer.
- Syntax of write: fileobject.write((char*) & NameOfObject, sizeof(name of object))
- Function write expects data type const char* as its first argument. The second argument of
write is an integer of type size specifying the number of bytes to be written.
- Here is an example that shows how to write a record to a random access file.
#include<fstream.h>
#include<conio.h>
#include<stdlib.h>
struct stud_info{
int id;
char name[20];
char fname[20];
float CGPA;
}student;
void main()
clrscr();
char filename[15];
ofstream outdata;
cin>>filename;
outdata.open(filename,ios::out);
if(outdata.fail())
getch();
exit(1);
//stud_info student;
cin>>student.id;
cin>>student.name;
cin>>student.fname;
cin>>student.CGPA;
outdata.seekp(((student.id)-1) * sizeof(student));
outdata.close();
getch();
- The above code uses the combination of ostream function seekp and write to store data at
exact locations in the file.
- Function seekp sets the put file-position pointer to a specific position in the file, then the
write outputs the data.
- 1 is subtracted from the student id when calculating the byte location of the record. Thus,
for record 1, the file position pointer is set to the byte 0 of the file.
- The istream function read inputs a specified number of bytes from the current position in
the specified stream into an object.
- The syntax of read : read((char*)&name of object, sizeof(name of object));
- Function read requires a first argument of type char *. The second argument of write is an
integer of type size specifying the number of bytes to be read.
- Here is a code that shows how to read a random access record from a file.
#include<fstream.h>
#include<conio.h>
#include<stdlib.h>
struct stud_info{
int studid;
char name[20];
char fname[20];
float CGPA;
};
void main()
clrscr();
ifstream indata;
char filename[15];
cin>>filename;
indata.open(filename,ios::in);
if(indata.fail())
getch();
exit(1);
stud_info student;
int sid;
cin>>sid;
indata.seekg((sid-1) * sizeof(student));
cout<<"\nstudent id : "<<student.studid;
indata.close();
getch();
- Command line argument means facility by which you can supply arguments to the main()
function. These arguments are supplied to the program when the main function is called
from the command line. Eg. c:\> file-name arg1 arg2
- Where file-name is the name of file(the program) and arg1, arg2 are arguments passed to
the program.
- If we want to pass arguments to the main function, then main function should be written as
follow.
Return type main(int argc, char * argv[])
- The first argument argc represents the number of arguments in a command line. The
second argument argv is an array of character type pointers that points to the command
line arguments. Argc is known as argument counter and argv is called argument vector.
- C:\> student A B. the value of argc is 3 (student, A & B) and the argv would be an array of
three pointers to string as follows:
Argv[0] – points to student
Argv[1] – points to A
Argv[2] – points to B
- note that argv[0] always reperesents the command name that invokes the program.
- Here is a sample command line argument code
#include<fstream.h>
#include<conio.h>
#include<stdlib.h>
void main(int argc, char *argv[])
{
clrscr();
char ch;
if(argc < 3)
{