Lesson 1: What is Programming?
Formally: "A program is a
precise sequence of steps to solve a particular problem."
At its most basic level, programming
a computer simply means telling it what to do. Without these instructions or
programs computers are merely dumb machines. Computers are incredibly stupid.
They do exactly what we tell them to do: no more, no less-- unlike human
beings. Computers can't think by themselves. In this sense, they differ from human
beings. For example, if someone asks you, “What is the time?”, “Time please?”
or just, “Time?” you understand anyway that he is asking the time but computer
is different. Instructions to the computer should be explicitly stated.
Computer will tell you the time only if you ask it in the way you have
programmed it. When you're programming, it helps to be able to "think'' as
stupidly as the computer does, so that you are in the right frame of mind for
specifying everything in minute detail, and not assuming that the right thing
will happen by itself.
The Receipe of a good Program:
In order to design a program
effectively and properly we must have a recipe to follow. In the book name ‘How
to design programs’ by Matthias Felleisen and the co-worker, the idea of design
recipe has been stated very elegenlty as “Learning to design programs is like
learning to play soccer. A player must learn to trap a ball, to dribble with a
ball, to pass, and to shoot a ball. Once the player knows those basic skills,
the next goals are to learn to play a position, to play certain strategies, to
choose among feasible strategies, and, on occasion, to create variations of a
strategy because none fits.“ The author then continues to say that: “A
programmer is also very much like an architect, a composers, or a writer. They
are creative people who start with ideas in their heads and blank pieces of
paper. They conceive of an idea, form a mental outline, and refine it on paper
until their writings reflect their mental image as much as possible. As they
bring their ideas to paper, they employ basic drawing, writing, and playing
music to express certain style elements of a building, to describe a person's
character, or to formulate portions of a melody. They can practice their trade
because they have honed their basic skills for a long time and can use them on
an instinctive level. Programmers also form outlines, translate them into first
designs, and iteratively refine them until they truly match the initial idea.
Indeed, the best programmers edit and rewrite their programs many times until
they meet certain aesthetic standards. And just like soccer players,
architects, composers, or writers, programmers must practice the basic skills
of their trade for a long time before they can be truly creative. Design
recipes are the equivalent of soccer ball handling techniques, writing
techniques, arrangements, and drawing skills. “ Hence to design a program
properly, we must:
o Analyze a problem statement, typically expressed as a word problem.
o Express its essence, abstractly and with examples.
o Formulate statements and comments in a precise language.
o Evaluate and revise the activities in light of checks and tests and
o Pay attention to detail.
All of these are activities are very useful for a programmer.
o Analyze a problem statement, typically expressed as a word problem.
o Express its essence, abstractly and with examples.
o Formulate statements and comments in a precise language.
o Evaluate and revise the activities in light of checks and tests and
o Pay attention to detail.
All of these are activities are very useful for a programmer.
The above details are provided just for the sake of completeness and do not worry if the
above sounds greek to you. it is natural. If, after going half of the course,
you come back here then you will be in a perfect position to understand all of
this. We have kept this boring detail to a limit. There were other topics like
types of softwares, system software, application software, device drivers and
the dry background of C programming language, which we have not included in
this tutorial / guide. Our focus in this tutorial / guide is on programming C /
C++.
IMPORTANT:
From the next lesson we will be
doing actual programming. So, if you do not have one, get ready your C / C++
IDE. Bloodshed Dev C++ is a very popular IDE for C / C++, which you can
download from the following URLs:
Lesson 2: First C
Program
The best way to learn C is to start
coding right away. So here is our very first program in C.
# include <iostream.h>
main()
{
cout << "HELLO WORLD!";
}
main()
{
cout << "HELLO WORLD!";
}
Let's see what the above snippet of
code means.
# include
#include is a pre-processor directive. It is not part of our program; it is an instruction to the compiler. It tells the C compiler to include the contents of a file, in this case the system file iostream.h. The compiler knows that it is a system file, and therefore looks for it in a special place. The features of preprocessor will be discussed later. For the time being take this line on faith. You have to write this line. The sign # is known as HASH and also called SHARP.
#include is a pre-processor directive. It is not part of our program; it is an instruction to the compiler. It tells the C compiler to include the contents of a file, in this case the system file iostream.h. The compiler knows that it is a system file, and therefore looks for it in a special place. The features of preprocessor will be discussed later. For the time being take this line on faith. You have to write this line. The sign # is known as HASH and also called SHARP.
<iostream.h>
<iostream.h> is the name of the library definition file for all Input Output Streams. Your program will almost certainly want to send stuff to the screen and read things from the keyboard. iostream.h is the name of the file which has the code to do that work for you.
<iostream.h> is the name of the library definition file for all Input Output Streams. Your program will almost certainly want to send stuff to the screen and read things from the keyboard. iostream.h is the name of the file which has the code to do that work for you.
main()
The name main is special, in that the main is actually the one which is run when your program is used. A C program is made up of a large number of functions. Each of these is given a name by the programmer and they refer to each other as the program runs. C regards the name "main" as a special case and will run this function first. If you forget to have a main function, or mistype the name, the compiler will give you an error.
The name main is special, in that the main is actually the one which is run when your program is used. A C program is made up of a large number of functions. Each of these is given a name by the programmer and they refer to each other as the program runs. C regards the name "main" as a special case and will run this function first. If you forget to have a main function, or mistype the name, the compiler will give you an error.
Notice that there are parentheses
(“( )”, normal brackets) with main. Here the parentheses contain nothing. There
may be something written inside the parentheses. It will be discussed in later
lectures.
{}
Next, there is a curly bracket also called braces("{ }"). For every open brace there must be a matching close. Braces allows to group together pieces of a program. The body of main is enclosed in braces. Braces are very important in C; they enclose the blocks of the program.
Next, there is a curly bracket also called braces("{ }"). For every open brace there must be a matching close. Braces allows to group together pieces of a program. The body of main is enclosed in braces. Braces are very important in C; they enclose the blocks of the program.
cout
cout is known as out put stream in C and C++. Stream is a complicated thing, you will learn about it later. Think of a stream as a door. The data is transferred through stream, cout takes data from computer and sends it to the output. For the moment it is a screen of the monitor. hence we use cout for output.
cout is known as out put stream in C and C++. Stream is a complicated thing, you will learn about it later. Think of a stream as a door. The data is transferred through stream, cout takes data from computer and sends it to the output. For the moment it is a screen of the monitor. hence we use cout for output.
<<
The sign << indicates the direction of data. Here it is towards cout and the function of cout is to show data on the screen.
The sign << indicates the direction of data. Here it is towards cout and the function of cout is to show data on the screen.
“HELLO WORLD!”
The thing between the double quotes (“ ”) is known as character string. In C programming character strings are written in double quotes. Whatever is written after << and within quotation marks will be direct it to cout, cout will display it on the screen.
The thing between the double quotes (“ ”) is known as character string. In C programming character strings are written in double quotes. Whatever is written after << and within quotation marks will be direct it to cout, cout will display it on the screen.
The semicolon (;) at the end
of the above statement is very important. All C statements end with a semicolon
(;). Missing of a semicolon (;) at the end of statement is a
syntax error and compiler will report an error during compilation. If there is
only a semicolon (;) on a line than it will be called a null statement. i.e. it
does nothing. The extra semicolons may be put at the end but are useless and
aimless.
Comments in C:
Commenting the code is very much
encouraged in almost every programming language. The syntax of commenting the C
code is as under:
// for single line comments.....
/* This is a block of comments.
The comments end here.....*/
The comments end here.....*/
Comments do not add to the exe file,
so use them liberally.
|
Lesson 3: Variables and Data Types
|
During programming we need to store data. This data is
stored in variables. Variables are locations in memory
for storing data. The memory is divided into blocks. It
can be viewed as pigeon-holes. You can also think of it as PO Boxes. In post offices there are different boxes and each has an address. Similarly in memory, there is a numerical address
for each location of memory (block). It is difficult for us to handle these
numerical addresses in our programs. So we give a name
to these locations. These names are variables. We call them variables because
they can contain different values at different times.
The variable names in C may be started with a character or an underscore ( _ ). But avoid starting a name
with underscore ( _ ). C has many libraries which contain variables and
function names normally starting with underscore ( _ ). So your variable name
starting with underscore ( _ ) may conflict with these
variables or function names.In a program every variable has
o Name
o Type
o Size
o Value
The variables having a name, type and size (type and size will be discussed later) are just empty boxes. They are useless until we put some value in them. To put some value in these boxes is known as assigning values to variables. In C language, we use assignment operator for this purpose.
In C language equal-to-sign (=) is used as assignment operator. Do not confuse the algebraic equal-to with the assignment operator. In Algebra X = 2 means the value of X is 2, whereas in C language X = 2 (where X is a variable name) means take the value 2 and put it in the memory location labeled as X, afterwards you can assign some other value to X, for example you can write X = 10, that means now the memory location X contains the value 10 and the previous value 2 is no more there.
Data Types
A variable must have a data type associated with it, for example it can have data types like integer, decimal numbers, characters etc. The variable of type Integer stores integer values and a character type variable stores character value. The primary difference between various data types is their size in memory. Different data types have different sizes in memory depending on the machine and compilers. There are very few data types in C language. These data types are reserved words of C language. The reserve words can not be used as a variable name. Let’s take a look into different data types that the C language provides us to deal with whole numbers, real numbers and character data.Whole Numbers
The C language provides three data types to handle whole numbers.o int
o short
o long
The data type int is used to store whole numbers (integers). The integer type has a space of 4 bytes (32 bits for windows operating system) in memory. And it is mentioned as ‘int’ which is a reserved word of C, so we can not use it as a variable name. In programming before using any variable name we have to declare that variable with its data type. If we are using an integer variable named as ‘i’, we have to declare it as
int i ;
The above line is known as declaration statement. The declaration statement int i ; reserves 4 bytes of memory and labels it as ‘i’. This happens at the execution time.
We noted that the integer occupies four bytes in memory. So if we have to store a small integer like 5, 10 or 20, C provides another data type for storing small whole numbers which is called short. The size of short is two bytes and it can store numbers in range of -32768 to 32767. So if we are going to use a variable for which we know that it will not increase from 32767, for example the age of different people, then we use the data type short for age.
short age = 5;
On the other side if we have a very large whole number that cannot be stored in an int then we use the data type long provided by C. So when we are going to deal with very big whole numbers in our program, we use long data type. We use it in program as:
long x = 300500200;
Real Numbers
The C language provides two data types to deal with real numbers (numbers with decimal points e.g. 1.35, 735.251). The real numbers are also known as floating point numbers.o float
o double
To store real numbers, float data type is used. The float data type uses four bytes to store
a real number. Here is program that uses float data types.
float f = 325.32501
If we need to store a large real number which cannot be store in four bytes, then we use double data type. Normally the size of double is twice the size of float. In program we use it as:
double x = 345624.769123;
char Data Type
So far we have been looking on data types to store numbers, In programming we do need to store characters like a,b,c etc. For storing the character data C language provides char data type. By using char data type we can store characters in variables. While assigning a character value to a char type variable single quotes are used around the character as ‘a’./* This program uses short data type to store values */
#include <iostream.h>
main()
{
char x;
x = ’a’;
cout << “The character value in x = “;
cout << x;
}
Arithmetic Operators
In C language we have the usual arithmetic operators for addition, subtraction, multiplication and division. C also provides a special arithmetic operator which is called modulus. All these operators are binary operators which means they operate on two operands. So we need two values for addition, subtraction, multiplication, division and modulus.Addition +
Subtraction -
Multiplication *
Division /
Modulus %
There is one thing to note in division that when we use integer division (i.e. both operands are integers) yields an integer result. This means that if, for example, you are dividing 5 by 2 (5 / 2) it will give integer result as 2 instead of actual result 2.5. Thus in integer division the result is truncated to the whole number, the fractional part (after decimal) is ignored. If we want to get the correct result, then we should use float data type. The modulus operator returns the remainder after division. This operator can only be used with integer operands. The expression x % y returns the remainder after x is divided by y. For example, the result of 5 % 2 will be 1, 23 % 5 will be 3 and 107%10 will be 7.
Precedence of Operators
The arithmetic operators in an expression are evaluated according to their precedence. The precedence means which operator will be evaluated first and which will be evaluated after that and so on. In an expression, the parentheses ( ) are used to force the evaluation order. The operators in the parentheses ( ) are evaluated first. If there are nested parentheses then the inner most is evaluated first. The expressions are always evaluated from left to right. The operators *, / and % have the highest precedence after parentheses. These operators are evaluated before + and –operators. Thus + and – operators has the lowest precedence. It means that if there are * and + operators in an expression then first the * will be evaluated and then its result will be added to other operand. If there are * and / operators in an expression (both have the same precedence) then the operator which occurs first from left will be evaluated first and then the next, except you force any operator to evaluate by putting parentheses around it.
|
Lesson 4: Expressions
|
Let's try to implement what we have
learned so far:
Problem Statement:
Calculate the average age of a class
of five students. Prompt the user to enter the age of each student.
Solution:
Lets first sort out the problem. In
the problem we will take the ages of five students from the user. To store
these ages we will use five variables, one variable for each student’s age. As
the age is stored in whole numbers so we will use the variables of data type
int. The variables declaration statement in our program will be as follow:
int age1, age2, age3, age4, age5;
We have declared all the five variables in a single line by using comma separator ( , ). This is a short method to declare a number of variables of the same data type. After this we will add all the ages to get the total age and store this total age in a variable. Then we will get the average age of the five students by dividing this total age by 5. For the storage of total and average ages we need variables. For this purpose we use variable TotalAge for the total of ages and AverageAge for average of ages respectively.
int age1, age2, age3, age4, age5;
We have declared all the five variables in a single line by using comma separator ( , ). This is a short method to declare a number of variables of the same data type. After this we will add all the ages to get the total age and store this total age in a variable. Then we will get the average age of the five students by dividing this total age by 5. For the storage of total and average ages we need variables. For this purpose we use variable TotalAge for the total of ages and AverageAge for average of ages respectively.
int TotalAge, AverageAge;
We have declared AverageAge as int data type so it can store only whole numbers. The average age of the class can be in real numbers with decimal point (for example if total age is 88 then average age will be 17.6). But the division of integers will produce integer result only and the decimal portion is truncated. If we need the actual result then we should use real numbers (float or double) in our program. Now we have declared variables for storing different values. In the next step we prompt the user to enter the age of first student. We simply show a text line on the screen by using the statement:
We have declared AverageAge as int data type so it can store only whole numbers. The average age of the class can be in real numbers with decimal point (for example if total age is 88 then average age will be 17.6). But the division of integers will produce integer result only and the decimal portion is truncated. If we need the actual result then we should use real numbers (float or double) in our program. Now we have declared variables for storing different values. In the next step we prompt the user to enter the age of first student. We simply show a text line on the screen by using the statement:
cout << “Please enter the age
of first student : ” ;
So on the screen the sentence “Please enter the age of first student:” will appear.
cin >> age1;
Lets have a look on the statement cin >> age1; cin is the counter part of the cout. Here cin is the input stream that gets data from the user and assigns it to the variable on its right side. We know that the sign >> indicates the direction of the flow of data. In our statement it means that data comes from user and is assigned to the variable age1, where age1 is a variable used for storing the age entered for student1. Similarly we get the ages of all the students and store them into respective variables. When cin statement is reached in a program, the program stops execution and expects some input from the user. After entering the age, the user has to press the 'enter key'. Pressing 'enter key' conveys to the program that user has finished entering the input and cin assigns the input value to the variable on the right hand side which is age1 in this case.
So on the screen the sentence “Please enter the age of first student:” will appear.
cin >> age1;
Lets have a look on the statement cin >> age1; cin is the counter part of the cout. Here cin is the input stream that gets data from the user and assigns it to the variable on its right side. We know that the sign >> indicates the direction of the flow of data. In our statement it means that data comes from user and is assigned to the variable age1, where age1 is a variable used for storing the age entered for student1. Similarly we get the ages of all the students and store them into respective variables. When cin statement is reached in a program, the program stops execution and expects some input from the user. After entering the age, the user has to press the 'enter key'. Pressing 'enter key' conveys to the program that user has finished entering the input and cin assigns the input value to the variable on the right hand side which is age1 in this case.
Next, we add all these values and
store the result to the variable TotalAge. We use assignment operator for this purpose.
On the right hand side of the assignment operator, we write the expression to
add the ages and store the result in the variable, TotalAge on left hand side.
For this purpose we write the statement as follow:
TotalAge = age1 + age2 + age3 + age4
+ age5 ;
The expression on the right hand side uses many addition operators ( + ). As these operators have the same precedence, the expression is evaluated from left to right. Thus first age1 is added to age2 and then the result of this is added to age3 and then this result is added to age4 and so on. Now we divide this TotalAge by 10 and get the average age. We store this average age in the variable i.e. AverageAge by writing the statement:
The expression on the right hand side uses many addition operators ( + ). As these operators have the same precedence, the expression is evaluated from left to right. Thus first age1 is added to age2 and then the result of this is added to age3 and then this result is added to age4 and so on. Now we divide this TotalAge by 10 and get the average age. We store this average age in the variable i.e. AverageAge by writing the statement:
AverageAge = TotalAge / 10;
And at the end we display this average age on the screen by using the following statement:
And at the end we display this average age on the screen by using the following statement:
cout<<“The average age of the
students is: “<<AverageAge;
Here the string enclosed in the quotation marks, will be printed on the screen as it is and the value of AverageAge will be printed on the screen. The complete coding of the program is given below:
/* This program calculates the average age of a class of five students after prompting the user to enter the age of each student. */
#include <iostream.h>
main ()
{
// declaration of variables, the age will be in whole numbers
int age1, age2, age3, age4, age5;
int TotalAge, AverageAge;
// take ages of the students from the user
cout << “Please enter the age of student 1: ”;
cin >> age1;
cout << “Please enter the age of student 2: ”;
cin >> age2;
cout << “Please enter the age of student 3: ”;
cin >> age3;
cout << “Please enter the age of student 4: ”;
cin >> age4;
cout << “Please enter the age of student 5: ”;
cin >> age5;
// calculate the total age and average age
TotalAge = age1 + age2 + age3 + age4 + age5;
AverageAge = TotalAge / 5;
// Display the result ( average age )
cout << “Average age of class is: “ << AverageAge;
}
A sample output of the above program is given below.
Please enter the age of student 1: 12
Please enter the age of student 2: 13
Please enter the age of student 3: 11
Please enter the age of student 4: 14
Please enter the age of student 5: 13
Average age of class is: 12
In the above output the total age of the students is 63 and the actual average should be 12.6 but as we are using integer data types so the decimal part is truncated and the whole number 12 is assigned to the variable AverageAge.
Here the string enclosed in the quotation marks, will be printed on the screen as it is and the value of AverageAge will be printed on the screen. The complete coding of the program is given below:
/* This program calculates the average age of a class of five students after prompting the user to enter the age of each student. */
#include <iostream.h>
main ()
{
// declaration of variables, the age will be in whole numbers
int age1, age2, age3, age4, age5;
int TotalAge, AverageAge;
// take ages of the students from the user
cout << “Please enter the age of student 1: ”;
cin >> age1;
cout << “Please enter the age of student 2: ”;
cin >> age2;
cout << “Please enter the age of student 3: ”;
cin >> age3;
cout << “Please enter the age of student 4: ”;
cin >> age4;
cout << “Please enter the age of student 5: ”;
cin >> age5;
// calculate the total age and average age
TotalAge = age1 + age2 + age3 + age4 + age5;
AverageAge = TotalAge / 5;
// Display the result ( average age )
cout << “Average age of class is: “ << AverageAge;
}
A sample output of the above program is given below.
Please enter the age of student 1: 12
Please enter the age of student 2: 13
Please enter the age of student 3: 11
Please enter the age of student 4: 14
Please enter the age of student 5: 13
Average age of class is: 12
In the above output the total age of the students is 63 and the actual average should be 12.6 but as we are using integer data types so the decimal part is truncated and the whole number 12 is assigned to the variable AverageAge.
Examples of Expressions
We have already seen the precedence
of arithmetic operators. We have expressions for different calculations in
algebraic form, and in our programs we write them in the form of C statements.
Let’s discuss some more examples to get a better understanding.
We have no power operator in C, just
use * to multiply the same value.
While writing expressions in C we
should keep in mind the precedence of the operators and the order of evaluation
of the expressions (expressions are evaluated from left to right). Parentheses
are used in complicated expressions. Parentheses at wrong place can cause an
incorrect result. For example, a statement x = 2 + 4 * 3 results x = 14. As *
operator is of higher precedence, 4 * 3 is evaluated first and then result 12
is added to 4 which gives the result 14. We can rewrite this statement, with
the use of parentheses to show it clearly, that multiplication is performed
first. Thus we can write it as x = 2 + (4 * 3). But the same statement with
different parentheses like x = (2 + 4) * 3 will give the result 18, so we have
to be careful while using parenthesis and the evaluation order of the
expression.
Lesson 5: Conditionals and Logical Operators
In every day life, we are often
making decisions. In the previous lessons, we have written simple elementary
programs. For writing interesting and useful programs, we have to introduce the
decision making power in them. Now we will see what kind of decisions are there
in C/C++ programming language and how these can be used.
The statement used for decisions in
'C' language is known as the 'if statement'. The if statement has a simple
structure. That is:
if (condition)
{
statement;
statement;
.
.
statement;
}
if (condition)
{
statement;
statement;
.
.
statement;
}
The above statements mean, If
condition is true, then execute the statement or a group of statements. Here
the condition is a statement which explains the condition on which a decision
will be made. We can understand it from the example that A can become the
member of the basket ball team if he has a height more than six feet .In this
case, the condition will be if (A’s height is greater than six feet) A can be a
member of team We have written the condition in English language. Now let's see
how we can implement this in terms of variables, operators and C statements. In
the program, we will write the condition in parentheses, followed by a
statement or group of statements to be executed. Now here is the concept of
block of statements. We use braces { } to make a group (block) of a number of
statements. We put ‘{’ before first statement and ‘}’ after the last statement.
Let's consider a simple example to
explain the if statement. Suppose, we have ages of two students (say for the
time being we have got these ages in variables). These variables are age1 and
age2. Now we say that if the age1 is greater than age2, then display the
statement ‘Student 1 is older than student 2’.
#include <iostream.h>
main()
{
int age1, age2;
age1 = 12;
age2 = 10;
if (age1 > age2)
cout << “Student 1 is older than student 2”;
}
Here, in our code we see a new operator i.e. ‘ > ‘ (greater than) in the if statement. We need such operators while making decisions. These operators are called 'relational operators'.
main()
{
int age1, age2;
age1 = 12;
age2 = 10;
if (age1 > age2)
cout << “Student 1 is older than student 2”;
}
Here, in our code we see a new operator i.e. ‘ > ‘ (greater than) in the if statement. We need such operators while making decisions. These operators are called 'relational operators'.
Greater than >
Equal to = =
Less than <
Greater than or equal to >=
Less than or equal to <=
Not equal to !=
Note that there is no space between = =, >=, <= and !=. These are considered as single operators.
The operator == (equal to) is different from the operator =.
Equal to = =
Less than <
Greater than or equal to >=
Less than or equal to <=
Not equal to !=
Note that there is no space between = =, >=, <= and !=. These are considered as single operators.
The operator == (equal to) is different from the operator =.
If/else Structure
We have seen that the if structure
executes its block of statement(s) only when the condition is true, otherwise
the statements are skipped. The if/else structure allows the programmer to
specify that a different block of statement(s) is to be executed when the
condition is false. The structure of if/else selection is as follows.
if ( condition)
{
statement(s);
}
else
{
statement(s);
}
if ( condition)
{
statement(s);
}
else
{
statement(s);
}
Thus using this structure we can
write the construct of our program as
if (a >= b)
{
cout << " a is greater than or equal to b";
}
else
{
cout << " b is greater than a";
}
In this construct, the program checks the condition in if statement .If the condition is true, then the line "a is greater than b" is printed. Otherwise (if condition is not true), the statement related to else is executed and the message "b is greater than a" is printed.
if (a >= b)
{
cout << " a is greater than or equal to b";
}
else
{
cout << " b is greater than a";
}
In this construct, the program checks the condition in if statement .If the condition is true, then the line "a is greater than b" is printed. Otherwise (if condition is not true), the statement related to else is executed and the message "b is greater than a" is printed.
Logical Operators
There are many occasions when we
face complex conditions to make a decision. This means that a decision depends
upon more than one condition in different ways. Here we combine the conditions
with AND or OR. For example, a boy can be selected in basket ball team only if
he is more than 18 years old and has a height of 6 feet. In this statement a
boy who wants to be selected in the basket ball team must have both the
conditions fulfilled. This means that AND forces both the conditions to be
true. Similarly we say that a person can be admitted to the university if he
has a BCS degree OR BSC degree. In this statement, it is clear that a person
will be admitted to the university if he has any one of the two degrees.
In programming we use logical
operators ( && and || ) for AND and OR respectively with relational
operators. These are binary operators and take two operands. These operators
use logical expressions as operands, which return TRUE or FALSE. The &&
operator has a higher precedence than the || operator. An expressions
containing && or || is evaluated only until truth or
falsehood is known. Thus evaluation of the expression (age > 18) && (height > 6) will stop immediately if age > 18 is false (i.e. the entire expression is false) and continue if age > 18 is true (i.e. the entire expression could still be true if the condition height > 6 is true ).
falsehood is known. Thus evaluation of the expression (age > 18) && (height > 6) will stop immediately if age > 18 is false (i.e. the entire expression is false) and continue if age > 18 is true (i.e. the entire expression could still be true if the condition height > 6 is true ).
There is another logical operator
that is called logical negation. The sign ! is used for this operator. This
operand enables a programmer to ‘reverse’ the meaning of a condition. This is a
unary operator that has only a single condition as an operand. The operator !
is placed before a condition. If the original condition (without the ! operator)
is false then the ! operator before it converts it to true and the statements
attached to this are executed. Look at the following expression
if ( ! (age > 18 ))
cout << “The age is less than 18”;
cout << “The age is less than 18”;
Here the
cout statement will be executed if the original condition (age > 18) is
false because the ! operator before it reverses this false to true.
Lesson 6: Repetition Structures 1 (while Loops)
In our day to day life, most of the
things are repeated. Days and nights repeat themselves 30 times a month. Four
seasons replace each other every year. We can see similar phenomenon in the
practical life. For example, in the payroll system, some procedures are same
for all the employees. These are repeatedly applied while dealing with the
employees. So repetition is a very useful structure in the programming.
Therefore, we need some repetition structure in the programming language. There
are many looping constructs in C Language. The repetition structure we will
discuss in this lesson is 'while loop structure'. ‘while’ is also
a key word of 'C' so it cannot be used as a variable name. While means, 'do
it until the condition is true'. The use of while construct can be helpful
in repeating a set of instructions under some condition. We can also use curly
braces with while just like we used with if. If we omit to use the braces with
while construct, then only one statement after while will be repeatedly executed.
For good programming practices, always use braces with while irrespective of
the number of statements in while block. The syntax of while construct is as
under:
while ( Logical Expression ) {
statement1;
statement2;
………….
}
statement1;
statement2;
………….
}
The logical expression contains a
logical or relational operator. While this logical expression is true, the
statements will be executed repeatedly. When this logical expression becomes
false, the statements within the while block, will not be executed. Rather the
next statement in the program after while block, will be executed.
Sample Code:
/* This program calculate the sum of
first 1000 integers */
#include <iostream.h>
main()
{
//declaration of variables
int sum, number;
#include <iostream.h>
main()
{
//declaration of variables
int sum, number;
//Initialization of the variables
sum = 0;
number = 1;
// using the while loop to find out the sum of first 1000 integers starting from 1
while(number <= 1000)
{
// Adding the integer to the contents of sum
sum = sum + number;
// Generate the next integer by adding 1 to the integer
number = number + 1;
}
cout << "The sum of first 1000 integers starting from 1 is " << sum;
}
The output of the program is:
The sum of first 1000 integers starting from 1 is 500500
sum = 0;
number = 1;
// using the while loop to find out the sum of first 1000 integers starting from 1
while(number <= 1000)
{
// Adding the integer to the contents of sum
sum = sum + number;
// Generate the next integer by adding 1 to the integer
number = number + 1;
}
cout << "The sum of first 1000 integers starting from 1 is " << sum;
}
The output of the program is:
The sum of first 1000 integers starting from 1 is 500500
Overflow Condition:
We can change the condition in the
above code to 10000 or even more. Just try some more numbers. How far can you
go with the limit? We know that integers are allocated a fixed space in memory
(i.e. 32 bits in most PCs) and we can not store a number which requires more
bits than integer, into a variable of data type, int. If the sum of integers
becomes larger than this limit (i.e. sum of integers becomes larger than 32
bits can store), two things can happen here. The program will give an error
during execution, compiler can not detect such errors. These errors are known
as run time errors. The second thing is that 32 bits of the result will be
stored and extra bits will be wasted, so our result will not be correct as we
have wasted the information. This is called overflow. When we try to store
larger information in, than a data type can store, overflow condition occurs.
When overflow condition occurs either a run-time error is generated or wrong
value is stored.
Infinite Loop:
Consider the condition in the while
structure that is (number <= 1000) and in the while block the value of
number is changing (number = number + 1) to ensure that the condition is tested
again next time. If it is true, the while block is executed and so on. So in
the while block statements, the variable used in condition must change its
value so that we have some definite number of repetitions. What will happen if
we do not write the statement number = number + 1; in our program? The value of
number will not change, so the condition in the while loop will be true always
and the loop will be executed forever. Such loops in which the condition is
always true are known as infinite loops as there are infinite repetitions in
it.
Property of while loop:
The property of while loop is that
it may execute zero or more time. The while loop is terminated, when the
condition is tested as false.
Lesson 7: Repetition Structures (do-while Loops)
We have seen that there may be
certain situations when the body of while loop does not execute even a single
time. This occurs when the condition in while is false. In while loop, the
condition is tested first and the statements in the body are executed only when
this condition is true. If the condition is false, then the control goes
directly to the statement after the closed brace of the while loop. So we can
say that in while structure, the loop can execute zero or more times. There may
be situations where we may need that some task must be performed at least once.
For example, a computer program has a character stored from a-z. It gives to
user five chances or tries to guess the character. In this case, the task of
guessing the character must be performed at least once. To ensure that a block
of statements is executed at least once, C provides a do-while
structure. The syntax of do-while structure is as under:
do
{
statement(s);
}
while ( condition );
{
statement(s);
}
while ( condition );
Here we see that the condition is
tested after executing the statements of the loop body. Thus, the loop body is
executed at least once and then the condition in do while statement is tested.
If it is true, the execution of the loop body is repeated. In case, it proves
otherwise (i.e. false), then the control goes to the statement next to the do
while statement. This structure describes ‘execute the statements enclosed in
braces in do clause' when the condition in while clause is true. Broadly speaking,
in while loop, the condition is tested at the beginning of the loop before the
body of the loop is performed. Whereas in do-while loop, the condition is
tested after the loop body is performed. Therefore, in do-while loop, the body
of the loop is executed at least once.
Sample Code:
Let’s consider the example of
guessing a character. We have a character in the program to be guessed by the
user. Let’s call it ‘z’. The program allows five tries (chances) to the user to
guess the character. We declare a variable tryNum to store the number of tries.
The program prompts the user to enter a character for guessing. We store this
character in a variable c. We declare the variable c of type char. The data
type char is used to store a single character. We assign a character to a
variable of char type by putting the character in single quotes. Thus the
assignment statement to assign a value to a char variable will be as:
c = ‘a’;
Here we use the do-while construct.
In the do clause we prompt the user to enter a character. After getting
character in variable c from user, we compare it with our character i.e ‘z’. We
use if\else structure for this comparison. If the character is the same as ours
then we display a message to congratulate the user else we add 1 to tryNum
variable. And then in while clause, we test the condition whether tryNum is
less than or equal to 5 (tryNum <= 5). If this condition is true, then the
body of the do clause is repeated again. We do this only when the condition
(tryNum <= 5) remains true. If it is otherwise, the control goes to the
first statement after the do-while loop. If guess is matched in first or second
try, then we should exit the loop. We know that the loop is terminated when the
condition tryNum <= 5 becomes false, so we assign a value which is greater
than 5 to tryNum after displaying the message. Now the condition in the while
statement is checked. It proves false (as tryNum is greater than 5). So the
control goes out of the loop. First look here the flow chart for the program.
The code of the program is given below.
//This program allows the user to
guess a character from a to z
//do-while construct is used to allow five tries for guessing
# include <iostream.h>
main ( )
{
//declare & initialize variables
int tryNum = 0 ;
char c ;
// do-while construct, prompt the user to guess a number and compares it
do
{
cout << “Please enter a character between a-z for guessing : “ ;
cin >> c ;
//check the entered character for equality
if ( c == ‘z’)
{
cout << “Congratulations, Your guess is correct” ;
}
else
{
tryNum = tryNum + 1;
}
}
while ( tryNum <= 5 && c != ‘z’ );
}
The output of the program is given below.
Please enter a character between a-z for guessing : g
Please enter a character between a-z for guessing : z
Congratulations, Your guess is correct
//do-while construct is used to allow five tries for guessing
# include <iostream.h>
main ( )
{
//declare & initialize variables
int tryNum = 0 ;
char c ;
// do-while construct, prompt the user to guess a number and compares it
do
{
cout << “Please enter a character between a-z for guessing : “ ;
cin >> c ;
//check the entered character for equality
if ( c == ‘z’)
{
cout << “Congratulations, Your guess is correct” ;
}
else
{
tryNum = tryNum + 1;
}
}
while ( tryNum <= 5 && c != ‘z’ );
}
The output of the program is given below.
Please enter a character between a-z for guessing : g
Please enter a character between a-z for guessing : z
Congratulations, Your guess is correct
Lesson 8: Repetition Structures (for Loops)
Let’s see what we do in a loop. In a
loop, usually, we initialize variable(s) at first. Then we set a condition for
the continuation/termination of the loop. To meet the condition to terminate
the loop, we affect the condition in the body of the loop. If there is a
variable in the condition, the value of that variable is changed within the
body of the loop. If the value of the variable is not changed, then the
condition of termination of the loop will not meet and loop will become an
infinite one. So there are three things in a loop structure i.e. (i)
initialization, (ii) a continuation/termination condition and (iii) changing
the value of the condition variable, usually the increment of the variable
value. To implement these things, C provides a loop structure known as for
loop. This is the most often used structure to perform repetition tasks for
a known number of repetitions. The syntax of for loop is given below.
for ( initialization condition ;
continuation condition ; incrementing condition )
{
statement(s) ;
}
{
statement(s) ;
}
We see that a 'for statement'
consists of three parts. In initialization condition, we initialize some
variable while in continuation condition, we set a condition for the
continuation of the loop. In third part, we increment the value of the variable
for which the termination condition is set. Let's suppose, we have a variable
counter of type int. We write for loop in our program as:
for ( counter = 0 ; counter < 10
; counter = counter +1 )
{
cout << counter << endl;
}
{
cout << counter << endl;
}
This 'for loop' will print on the
screen 0, 1, 2 …. 9 on separate lines (as we use endl in our cout statement).
In for loop, at first, we initialize the variable counter to 0. And in the
termination condition, we write counter < 10. This means that the loop will
continue till value of counter is less than 10. In other words, the loop will
terminate when the value of counter is equal to or greater than 10. In the
third part of for statement, we write counter = counter + 1 this means that we
add 1 to the existing value of counter. We call it incrementing the variable.
Now let's see how this loop executes. When the control goes to for statement
first time, it sets the value of variable counter to 0, tests the condition
(i.e. counter < 10). If it is true, then executes the body of the loop. In
this case, it displays the value of counter which is 0 for the first execution.
Then it runs the incrementing statement (i.e. counter = counter + 1 ). Thus the
value of counter becomes 1. Now, the control goes to for statement and tests
the condition of continuation. If it is true, then the body of the loop is
again executed which displays 1 on the screen. The increment statement is again
executed and control goes to for statement. The same tasks are repeated. When
the value of counter becomes
10, the condition counter < 10 becomes false. Then the loop is terminated and control goes out of for loop. The point to be noted is that, the increment statement (third part of for statement) is
executed after executing the body of the loop. Thus for structure is equivalent to a while structure, in which, we write explicit statement to change (increment/decrement) the value of the condition variable after the last statement of the body. The for loop does this itself according to the increment statement in the for structure. There may be a situation where the body of for loop, like while loop, may not be executed even a single time. This may happen if the initialization value of the variable makes the condition false. The statement in the following for loop will not be executed even a single time as during first checking, the condition becomes false. So the loop terminates without executing the body of the loop.
10, the condition counter < 10 becomes false. Then the loop is terminated and control goes out of for loop. The point to be noted is that, the increment statement (third part of for statement) is
executed after executing the body of the loop. Thus for structure is equivalent to a while structure, in which, we write explicit statement to change (increment/decrement) the value of the condition variable after the last statement of the body. The for loop does this itself according to the increment statement in the for structure. There may be a situation where the body of for loop, like while loop, may not be executed even a single time. This may happen if the initialization value of the variable makes the condition false. The statement in the following for loop will not be executed even a single time as during first checking, the condition becomes false. So the loop terminates without executing the body of the loop.
Sample Code:
Let’s take an example to explain for
loop. We want to write a program that prints the table of 2 on the screen. In
this program, we declare a variable counter of type int. We use this variable
to multiply it by 2 with values 1 to 10. For writing the table of 2, we multiply
2 by 1, 2, 3 ... upto 10 respectively and each time display the result on
screen. So we use for loop to perform the repeated multiplication. Following is
the code of the program that prints the table of 2.
//This program display the table of
2 up to multiplier 10
# include <iostream.h>
main ( )
{
int counter;
//the for loop
for ( counter = 1 ; counter <= 10 ; counter = counter + 1)
{
cout << “2 x “ << counter << “ = “ << 2 * counter << “\n” ;
}
}
# include <iostream.h>
main ( )
{
int counter;
//the for loop
for ( counter = 1 ; counter <= 10 ; counter = counter + 1)
{
cout << “2 x “ << counter << “ = “ << 2 * counter << “\n” ;
}
}
This is a simple program. In the for
statement, we initialize the variable counter to 1 as we want the
multiplication of 2 starting from 1. In the condition clause, we set the
condition counter <= 10 as we want to repeat the loop for 10 times. And in
the incrementing clause, we increment the variable counter by 1. In the body of
the for loop, we write a single statement with cout. This single statement
involves different tasks. The portion ‘<< “2 x “’ displays the string “2
x “ on the screen.
After this, the next part ‘<< counter’ will print the value of counter. The ‘<< “ = ”’ will display ‘ = ‘ and then the next part ‘<< 2 * counter’ will display the result of 2 multiply by counter and the last <<”\n” ( the new line character) will start a new line and on the subsequent iterations the cout will print the same line by incrementing the count by 1. The complete output of the above code is as under:
After this, the next part ‘<< counter’ will print the value of counter. The ‘<< “ = ”’ will display ‘ = ‘ and then the next part ‘<< 2 * counter’ will display the result of 2 multiply by counter and the last <<”\n” ( the new line character) will start a new line and on the subsequent iterations the cout will print the same line by incrementing the count by 1. The complete output of the above code is as under:
2
x 1 = 2
2 x 2 = 4
2 x 3 = 6
2 x 4 = 8
2 x 5 = 10
2 x 6 = 12
2 x 7 = 14
2 x 8 = 16
2 x 9 = 18
2 x 10 = 20
2 x 2 = 4
2 x 3 = 6
2 x 4 = 8
2 x 5 = 10
2 x 6 = 12
2 x 7 = 14
2 x 8 = 16
2 x 9 = 18
2 x 10 = 20
Increment Decrement Operators:
We have seen that in while, do-while
and for loop we write a statement to increase the value of a variable. For
example, we used the statements like counter = counter + 1; which adds 1 to the
variable counter. This increment statement is so common that it is used almost
in every repetition structure (i.e. in while, do-while and for loop). The C
language provides a unary operator that increases the value of its operator by
1. This operator is called increment operator and sign ++ is used for this. The
statement counter = counter + 1; can be replaced with the statement
counter ++ ;
The statement counter++ adds 1 to
the variable counter. There is also an operator -- called decrement operator.
This operator decrements, the value of its operand by 1.The increment operator
is further categorized as pre-increment and post-increment. Similarly, the
decrement operator, as pre-decrement and post-decrement. In pre-increment, we
write the sign before the operand like ++j while in post-increment, the sign ++
is used after the operand like j++. If we are using only variable increment,
pre or post increment does not matter. In this case, j++ is equivalent to ++j.
The difference of pre and post increment matters when the variable is used in
an expression where it is evaluated to assign a value to another variable. If
we use pre-increment ( ++j ), the value of j is first increased by 1. This new
value is used in the expression. If we use post increment ( j++ ),the value of
j is used in the expression. After that it is increased by 1. Same is the case
in pre and post decrement. If j = 5, and we write the expression:
x = ++ j ;
After the evaluation of this
expression, the value of x will be 6 (as j is incremented first and then is
assigned to x). The value of j will also be 6 as ++ operator increments it by
1. If j = 5, and we write the expression:
x = j++ ;
Then after the evaluation of the
expression, the value of x will be 5 (as the value of j is used before
increment) and the value of j will be 6. The same phenomenon is true for the
decrement operator with the difference that it decreases the value by 1.
There may be cases when we are
incrementing or decrementing the value of a variable by a number other than 1.
For example, we write counter = counter + 5; or j = j – 4;. Such assignments
are very common in loops, so C provides operators to perform this task in
short. These operators do two things they perform an action (addition,
subtraction etc) and do some assignment. These operators are +=, -=, *=, /= and
%=. These operators are compound assignment operators. These operators assign a
value to the left hand variable after performing an action (i.e. +, -, *, / and
%). The use of these operators is explained by the following examples. Let’s
say we have an expression, counter = counter + 5;. The equivalent of this
expression is counter += 5;. The statement counter += 5; does two tasks. At
first, it adds 5 to the value of counter and then assigns this result to
counter. Similarly the following expressions:
x = x + 4 ;
x = x - 3 ;
x = x * 2 ;
x = x / 2 ;
x = x % 3;
x = x - 3 ;
x = x * 2 ;
x = x / 2 ;
x = x % 3;
can be written in equivalent short
statements using the operators ( +=, -=, *=, /=, %= ) as follows:
x += 4 ;
x -= 3 ;
x *= 2;
x /= 2;
x %= 3 ;
x -= 3 ;
x *= 2;
x /= 2;
x %= 3 ;
Note that there is no space between
these operators. These are treated as single signs.
Lesson 9: Switch, Break and Continue Statements
Sometimes, we have multiple
conditions and take some action according to each condition. For example, we
want to print description of the grade of a student. If the student has grade
‘A’ we print ‘Excellent’ and 'Very good', 'good', 'poor' and 'fail' for grades
B, C, D, and F respectively. Now we have to see how this multi-condition
situation can be applied in a program. We have a tool for decision making i.e.
'if statement'. We can use 'if statement' to decide what description for a
grade should be displayed. But in such a situation where we have multiple
conditionas the C language provides us a stand-alone construct to handle these
instances. This construct is switch structure. The switch structure is a
multiple-selection construct that is used in such cases (multi way decisions)
to make the code more efficient and easy to read and understand. The syntax of
switch statement is as follows:
switch ( variable/expression )
{
case constant1 : statementLlist1 ;
case constant2 : statementLlist2 ;
:
:
case constantN : statementListN ;
default : statementList ;
}
{
case constant1 : statementLlist1 ;
case constant2 : statementLlist2 ;
:
:
case constantN : statementListN ;
default : statementList ;
}
In the switch statement, there
should be an integer variable (char is also allowed) or an expression which
must evaluate to an integer type (whole numbers only, the decimal numbers 2.5,
14.3 etc are not allowed). We can’t use compound conditions (i.e. the
conditions that use logical operators && or ||) in switch statement and
in case statements. The constants also must be integer constants (which include
char). We can’t use a variable name with the case key word. The default
statement is optional. If there is no case which matches the value of the
switch statement, then the statements of default are executed. The switch
statement takes the value of the variable, if there is an expression then it
evaluates the expression and after that looks for its value among the case
constants. If the value is found among the constants listed in cases, the
statements in that statementList are executed. Otherwise, it does nothing.
However if there is a default (which is optional), the statements of default
are executed. Thus our previous grade example will be written in switch
statement as below:
switch ( grade )
{
case ‘A’ : cout << “Excellent” ;
case ‘B’ : cout << “Very Good” ;
case ‘C’ : cout << “Good” ;
case ‘D’ : cout << “Poor” ;
case ‘F’ : cout << “Fail” ;
}
{
case ‘A’ : cout << “Excellent” ;
case ‘B’ : cout << “Very Good” ;
case ‘C’ : cout << “Good” ;
case ‘D’ : cout << “Poor” ;
case ‘F’ : cout << “Fail” ;
}
We know that C language is 'case
sensitive'. In this language, ‘A’ is different from ‘a’. Every character has a
numeric value which is stored by the computer.. The numeric value of a
character is known as ASCII code of the character. The ASCII code of small
letters (a, b, c etc ) are different from ASCII code of capital letters (A, B,
C etc). We can use characters in switch statement as the characters are
represented as whole numbers inside the computers. Now we will see how the use
of ' the letter a' instead of 'A' can affect our program. We want our program
to be user- friendly. We don’t want to restrict the user to enter the grade in
capital letters only. So we have to handle both small and capital letters in
our program. Here comes the limitations of switch statement. We can’t say in
our statement like:
case ‘A’ or ‘a’ : statements ;
We have to make two separate cases
so we write:
case ‘A” :
case ‘a’ :
statements;
case ‘a’ :
statements;
In the switch statement, the cases
fall through the case which is true. All the statements after that case will be
executed right down to the end of the switch statement. This is very important
to understand it. Let's suppose that the user enters grade ‘B’. Now the case
‘A’ is skipped. Next case ‘B’ matches and statement cout << “Very Good” ;
is executed. After that, all the statements will be executed. So cout <<
“Good” ; cout << “Poor” ;and cout << “Fail” ; will be executed
after one another. We don’t want this to happen. We want that when a case
matches, then after executing its statement, the control should jump out of the
switch statement leaving the other cases. For this purpose we use a key word
break.
Break Statement
The break statement interrupts the
flow of control. We have seen in switch statement that when a true case is
found, the flow of control goes through every statement downwards. We want that
only the statements of true case should be executed and the remaining should be
skipped. For this purpose, we use the break statement. We write the break
statement after the statements of a case. Thus, when a true case is found and
its statements are executed then the break statement interrupts the flow of
control and the control jumps out of the switch statement. The break statement
is necessary in switch structure, without it the switch structure becomes
illogic. As without it all the statement will execute after first match case is
found.
The above code does nothing if the
grade is other than these five categories (i.e. A, B, C, D and F). To handle all
the possibilities of grade input, we write a default statement after the last
case. The statement in this default case is executed if no case matches the
grade. So in our program, we can write the default statement after the last
case as under.
default : cout << “Please
enter grade from A to D or F ” ;
The break statement is also used in
decision structures other than switch structure. We have seen that in while,
do-while and for loops, we have to violate some condition explicitly to
terminate the loop before its complete repetitions. In these loops, we can use
the break statement to exit a loop. When a break statement is encountered in a
loop, the loop terminates immediately. The control exits the inner most loop if
there are nested loops. The control passes to the statement after the loop.
Sample Code:
/*This program gets a grade from
user and displays a description accordingly*/
# include <iostream.h>
main ( )
{
char grade ;
cout << “Please enter the student’s grade : ” ;
cin >> grade ;
switch ( grade )
{
case ‘A’ : // grade was upper case A
case ‘a’ : // grade was lower case a
cout << “Excellent” ;
break : // necessary to exit switch
case ‘B’ : // grade was upper case B
case ‘b’ : // grade was lower case b
cout << “Very Good” ;
break : // necessary to exit switch
case ‘C’ : // grade was upper case C
case ‘c’ : // grade was lower case c
cout << “Good” ;
break : // necessary to exit switch
case ‘D’ : // grade was upper case D
case ‘d’ : // grade was lower case d
cout << “Poor” ;
break : // necessary to exit switch
case ‘F’ : // grade was upper case F
case ‘f’ : // grade was lower case f
cout << “Fail” ;
break : // necessary to exit switch
default :
cout << “Please enter grade from A to D or F ” ;
}
}
A sample out put of the program is shown here.
# include <iostream.h>
main ( )
{
char grade ;
cout << “Please enter the student’s grade : ” ;
cin >> grade ;
switch ( grade )
{
case ‘A’ : // grade was upper case A
case ‘a’ : // grade was lower case a
cout << “Excellent” ;
break : // necessary to exit switch
case ‘B’ : // grade was upper case B
case ‘b’ : // grade was lower case b
cout << “Very Good” ;
break : // necessary to exit switch
case ‘C’ : // grade was upper case C
case ‘c’ : // grade was lower case c
cout << “Good” ;
break : // necessary to exit switch
case ‘D’ : // grade was upper case D
case ‘d’ : // grade was lower case d
cout << “Poor” ;
break : // necessary to exit switch
case ‘F’ : // grade was upper case F
case ‘f’ : // grade was lower case f
cout << “Fail” ;
break : // necessary to exit switch
default :
cout << “Please enter grade from A to D or F ” ;
}
}
A sample out put of the program is shown here.
Please
enter the student’s grade : b
Very Good
Very Good
continue Statement:
There is another statement relating
to loops. This is the continue statement. Sometimes we have a lot of code in
the body of a loop. The early part of this code is common that is to be
executed every time (i.e. in every iteration of loop) and the remaining portion
is to be executed in certain cases and may not be executed in other cases. But
the loop should be continuous. For this purpose, we use the continue
statement. Like the break statement, the continue statement is written in a
single line. We write it as continue ; The continue forces the immediate next iteration of the
loop. So the statements of the loop body after continue are not executed. The
loop starts from the next iteration when a continue statement is encountered in
the body of a loop.
goto Statement:
There is a statement in the computer
languages COBOL, FORTRON and C. This statement is goto statement. The goto is
an unconditional branch of execution. The goto statement is used to jump the
control anywhere (back and forth) in a program.
The goto statement is defined just
for the sake of completeness and its use is not recommended. Because in such
programs, where to goto statement is used, it is very difficult, for a
programmer, to keep the track of execution as the control jumps from one place
to the other and from there to anywhere else. We call this kind of traditional
code as spagatti code. It is very difficult to trace out the way of execution
and figure out what the program is doing. And debugging and modifying such
programs is very difficult. When structured programming was started, it was
urged not to use the goto statement. Though goto is there in C language but we
will not use it in our programs. We will adopt the structured approach. All of
our programs will consist of sequences, decisions and
loops.
loops.
Lesson 10: Functions
A Function is
a stand-alone block of code that performs a specific task. For example to find
the square of a given integer. The functions are like subtasks. They receive
some information, do some process and provide a result. Functions are invoked
through a calling program. Calling program does not need to know what the
function is doing and how it is performing its task. There is a specific
function-calling methodology. The calling program calls a function by giving it
some information and receives the result. We have a main ( ) in every C
program. ‘main ( )’ is also a function. When we write a function, it must start
with a name, parentheses, and surrounding braces just like with main ( ).
Functions are very important in code reusing. There are two categories of
functions:
1. Functions that return a value
2. Functions that do not return a value
Suppose, we have a function that calculates the square of an integer such that function will return the square of the integer. Similarly we may have a function which displays some information on the screen so this function is not supposed to return any value to the calling program.
1. Functions that return a value
2. Functions that do not return a value
Suppose, we have a function that calculates the square of an integer such that function will return the square of the integer. Similarly we may have a function which displays some information on the screen so this function is not supposed to return any value to the calling program.
Structure of a Function
The declaration syntax of a function
is as follows:
return-value-type function-name(
argument-list )
{
declarations and statements
}
{
declarations and statements
}
The first line is the function
header and the declaration and statement part is the body of the function.
return-value_type:
Function may or may not return a
value. If a function returns a value, that must be of a valid data type. Return
type may be int, float, char or any other valid data type. The keyword return
is used to return some value from the function. It does two things, returns
some value to the calling program and also exits from the function. We can only
return a value (a variable or an expression which evaluates to some value) from
a function. The data type of the returning variable should match
return_value_type data type. There may be some functions which do not return
any value. For such functions, the return_value_type is void. ‘void’ is a
keyword of ‘C’ language. The default return_value_type is of int data type i.e.
if we do not mention any return_value_type with a function, it will return an
int value.
Function-name:
The function can have any name
following the rules of a variable name, but it should have a self-explanatory
name like square, squareRoot, circleArea etc.
argument-list:
Argument list contains the
information which we pass to the function. Some functions do not need any
information to perform the task. In this case, the argument list for such
functions will be empty. Arguments to a function are of valid data type like int
number, double radius etc.
Declarations and Statements:
This is the body of the function. It
consists of declarations and statements. The task of the function is performed
in the body of the function.
Example Code:
//This function calculates the
square of a number and returns it.
int square(int number)
{
int result = 0;
result = number * number;
return result;
}
int square(int number)
{
int result = 0;
result = number * number;
return result;
}
Calling Mechanism:
How a program can use a function? It
is very simple. The calling program just needs to write the function name and
provide its arguments (without data types). It is important to note that while
calling a function, we don’t write the return value data type or the data types
of arguments.
Example Code:
//This program calculates the square
of a given number
#include <iostream.h>
main()
{
int number, result;
#include <iostream.h>
main()
{
int number, result;
result = 0;
number = 0;
// Getting the input from the user
cout << “Please enter the number to calculate the square ”;
cin >> number;
// Calling the function square(int number)
result = square(number);
cout << “ The square of “ << number << “ is “ << result;
}
number = 0;
// Getting the input from the user
cout << “Please enter the number to calculate the square ”;
cin >> number;
// Calling the function square(int number)
result = square(number);
cout << “ The square of “ << number << “ is “ << result;
}
Declaration and Definition of a Function
Declaration and definition are two
different things. Declaration is the prototype of the function, that includes
the return type, name and argument list to the function and definition is the
actual function code. Declaration of a function is also known as signature of a
function. As we declare a variable like int x; before using it in our program,
similarly we need to declare function before using it. Declaration and
definition of a function can be combined together if we write the complete
function before the calling functions. Then we don’t need to declare it
explicitly. If we have written all of our functions in a different file and we
call these functions from main( ) which is written in a different file. In this
case, the main( ) will not be compiled unless it knows about the functions
declaration. Therefore we write the declaration of functions before the main( )
function. Function declaration is
a one line statement in which we write the return type, name of the function and the data type of arguments. Name of the arguments is not necessary. The definition of the function contains the complete code of the function. It starts with the declaration statement with the addition that in definition, we do write the names of the arguments. After this, we write an opening brace and then all the statements, followed by a closing brace.
a one line statement in which we write the return type, name of the function and the data type of arguments. Name of the arguments is not necessary. The definition of the function contains the complete code of the function. It starts with the declaration statement with the addition that in definition, we do write the names of the arguments. After this, we write an opening brace and then all the statements, followed by a closing brace.
Declaration:
int square ( int );
Definition:
int square ( int number)
{
return (number * number ) ;
}
{
return (number * number ) ;
}
Example Code:
//This program calculates the square
of a given number
#include <iostream.h>
// Function declarations.
int square(int);
main()
{
int number, result;
result = 0;
number = 0;
cout << “Please enter the number to calculate the square ”;
cin >> number;
// Calling the function square(int number)
result = square(number);
cout << “ The square of “ << number << “ is “ << result;
}
// function to calculate the square of a number
int square ( int number)
{
return (number * number ) ;
}
#include <iostream.h>
// Function declarations.
int square(int);
main()
{
int number, result;
result = 0;
number = 0;
cout << “Please enter the number to calculate the square ”;
cin >> number;
// Calling the function square(int number)
result = square(number);
cout << “ The square of “ << number << “ is “ << result;
}
// function to calculate the square of a number
int square ( int number)
{
return (number * number ) ;
}
Lesson 11: Header Files
We have already been using a header
file from day-zero. We used to write at the top before the start of the main()
function <iostream.h>, with ‘.h’ as an extension, you might have got the
idea that it is a header file. Now we will see why a Header file is used. In
the previous lessons, we discussed a little bit about Function Prototypes. One
thing is Declaration and other is Definition. Declaration can also be called as
'Prototype'. Normally, if we have lot of functions and want to use them in some
other function or program, then we are left with only one way i.e. to list the
prototypes of all of them before the body of the function or program and then
use them inside the function or program. But for frequent functions inside a
program, this technique increases the complexity (of a program). This problem
can be overcome by putting all these function prototypes in one file and
writing a simple line of code for including the file in the program. This code
line will indicate that this is the file, suppose 'area.h' containing all the
prototypes of the used functions and see the prototypes from that file. This is
the basic concept of a header file. So what we can do is:
- Make our own header file which is
usually a simple text file with '.h' extension ('.h' extension is not mandatory
but it is a rule of good programming practice).
- Write function prototypes inside that file. (Recall that prototype is just a simple line of code containing return value, function name and an argument list of data types with semi-colon at the end.)
- That file can be included in your own program by using the ‘#include’ directive and that would be similar to explicitly writing that list of function prototypes.
- Write function prototypes inside that file. (Recall that prototype is just a simple line of code containing return value, function name and an argument list of data types with semi-colon at the end.)
- That file can be included in your own program by using the ‘#include’ directive and that would be similar to explicitly writing that list of function prototypes.
Function prototypes are not the only
thing that can be put into a header file.There are some preprocessor directives
which we are going to cover later. At the moment, we will discuss about
‘#define’. With the help of #define we can define the constants of our programs
like the value of pi the header files and use them in our programs without
declaring them again. We define the onstants using this preprocessor directive
as:
#define pi 3.1415926
Scope of Identifiers
An 'Identifier' means any name that
the user creates in his/her program. These names can be of variables, functions
and labels. Here the scope of an identifier means its visibility. We will focus
Scope of Variables in our discussion. Suppose we write the function:
void func1()
{
int i;
. . . //Some other lines of code
int j = i+2; //Perfectly alright
. . .
}
{
int i;
. . . //Some other lines of code
int j = i+2; //Perfectly alright
. . .
}
Now this variable ‘i’ can be used in
any statement inside the function func1(). But consider this variable being
used in a different function like:
void func2()
{
int k = i + 4; //Compilation error
. . .
}
{
int k = i + 4; //Compilation error
. . .
}
The variable ‘i’ belongs to func1()
and is not visible outside that. In other words, ‘i’ is local to func1(). To
understand the concept of scope further, we have to see what are Code Blocks? A
code block begins with ‘{‘ and ends with ‘}’.Therefore, the body of a function
is essentially a code block. Nonetheless, inside a function there can be
another block of code like 'for loop' and 'while loop' can have their own
blocks of code respectively. Therefore, there can be a hierarchy of code
blocks. A variable declared inside a code block becomes the local variable for
that for that block.
It is not visible outside that block. See the code below:
It is not visible outside that block. See the code below:
void func()
{
int outer; //Function level scope
. . .
{
int outer; //Function level scope
. . .
{
int inner; //Code block level scope
inner = outer; //No problem
. . .
}
inner ++; //Compilation error
}
int inner; //Code block level scope
inner = outer; //No problem
. . .
}
inner ++; //Compilation error
}
Please note that variable ‘outer’ is
declared at function level scope and variable ‘inner’ is declared at block
level scope. The ‘inner’ variable declared inside the inner code block is not
visible outside it . In other words, it is at inner code block scope level. If
we want to access that variable outside its code block, a compilation error may
occur.
Global Variables
Now, is there a way that we declare
a variable only once and then use it inside all functions. We have already done
a similar task when we wrote a function prototype outside the body of all the
functions. The same thing applies to declaration of variables. You declare
variables outside of a function body (so that variable declarations are not part
of any function) and they become visible and accessible inside all functions of
that file. Notice that we have just used a new word ‘file’. A file or a source
code file with extension ‘.c’ or ‘.cpp’ can have many functions inside. A file
will contain one main() function maximum and rest of the functions as many as
required. If you want a variable to be accessible from within all functions,
you declare the variable outside the body of any function like the following
code snippet has declared such a variable ‘size’ below.
#include <iostream.h>
. . .
// Declare your global variables here
int size;
. . .
int main( … )
{
. . .
}
. . .
// Declare your global variables here
int size;
. . .
int main( … )
{
. . .
}
Now, this ‘size’ is visible in all
functions including main(). We call this as 'file scope variable' or a 'global
variable'.
Lesson 12: Function Calling
|
When it comes to function calling
mechanism of C or C++, we have two options available.
1. Function Calling by Value
2. Fuction Calling by Reference.
In the following text we explain both of the function calling mechanisms of C / C++ in some detail.
1. Function Calling by Value
2. Fuction Calling by Reference.
In the following text we explain both of the function calling mechanisms of C / C++ in some detail.
Function Calling (Call by Value):
The default function calling
mechanism of C is a 'Call by Value'. It means that when we call a function and
pass some arguments (variables) to it, we are passing a copy of the arguments
(variables) instead of original variables. The copy reaches to the function
that uses it in whatever way it wants and returns it back to the calling
function. The passed copy of the variable is used and
original variable is not touched. The default of C is 'Call by Value'. It is better to use it as it saves us from unwanted side effects. Relatively, 'Call by Reference' is a bit complex but it may be required sometimes when we want the actual variable to be changed by the function being called.
original variable is not touched. The default of C is 'Call by Value'. It is better to use it as it saves us from unwanted side effects. Relatively, 'Call by Reference' is a bit complex but it may be required sometimes when we want the actual variable to be changed by the function being called.
Let's consider an example to
comprehend 'Call by Value' and how it works. Suppose we write a main() function
and another small function f(int) to call it from main(). This function f( )
accepts an integer, doubles it and returns it back to the main() function. Our
program would look like this:
#include <iostream.h>
void f(int); //Prototype of the function
void main()
{
int i;
i = 10;
cout << “\n” << ” In main(), the value of i is: “ << i;
f(i);
cout <<“\n” << ” Back in main(), the value of i is: “ << i;
}
void f (int i)
{
i *= 2;
cout << “\n” << “ In f(), the value of i is: “ << i;
}
void f(int); //Prototype of the function
void main()
{
int i;
i = 10;
cout << “\n” << ” In main(), the value of i is: “ << i;
f(i);
cout <<“\n” << ” Back in main(), the value of i is: “ << i;
}
void f (int i)
{
i *= 2;
cout << “\n” << “ In f(), the value of i is: “ << i;
}
The output of this program is as
under:
In main(), the value of i is: 10
In f(), the value of i is: 20
Back in main(), the value of i is: 10
In main(), the value of i is: 10
In f(), the value of i is: 20
Back in main(), the value of i is: 10
As the output shows the value of the
variable ‘i’ inside function main() did not change, it proves the point that
the call was made by value.
Function Calling (Call by Reference):
We would like to use 'call by
reference' while using a function to change the value of the original variable.
Let's consider the square(double) function again, this time we want the
original variable ‘x’ to be squared. For this purpose, we passed a variable to
the square() function and as a result, on the contrary to the ‘Call by Value’,
it affected the calling functions original variable. So these kinds of
functions are ‘Call by Reference’ functions. Let us see, what actually happens
inside Call by Reference? As apparent from the name ‘By Reference’, we are not
passing the value itself but someform of reference or address. To understand
this, you can think in terms of variables which are names of memory locations.
We always access a variable by its name (which in fact is accessing a memory
location), a variable name acts as an address of the memory location of the
variable.If we want the called function to change the value of a variable of
the calling function, we must pass the address of that variable to the called
function. Thus, by passing the address of the variable to the called function,
we convey to the function that the number you should change is lying inside
this passed memory location, square it and put the result again inside that
memory location. When the calling function gets the control back after calling
the called function, it gets the changed value back in the same memory
location. In summary, while using the call by reference method, we can’t pass
the value. We have to pass the memory address of the value. This introduces a
new mechanism which is achieved by using ‘&’ (ampersand) operator in C language.
This ‘&’ operator is used to
get the address of a variable. Let's look at a function, which actually is a modification of our previous square() function.
get the address of a variable. Let's look at a function, which actually is a modification of our previous square() function.
#include <iostream.h>
void square(double);
void main()
{
double x;
x = 123.456;
cout << “\n” << “ In main(), before calling square(), x = “ << x;
square(&x); //Passing address of the variable x
cout << “\n” << “ In main(), after calling square(), x = “ << x;
}
void square(double*x)//read as:x is a pointer of type double
{
*x = *x * *x; //Notice that there is no space in *x
}
void square(double);
void main()
{
double x;
x = 123.456;
cout << “\n” << “ In main(), before calling square(), x = “ << x;
square(&x); //Passing address of the variable x
cout << “\n” << “ In main(), after calling square(), x = “ << x;
}
void square(double*x)//read as:x is a pointer of type double
{
*x = *x * *x; //Notice that there is no space in *x
}
Here *x means whatever the x points
to and &x means address of the variable x. We will discuss Pointers in
detail later. We are calling function square(double*) with the statement
square(&x) that is actually passing the address of the variable x , not its
value. In other words, we have told a box
number to the function square(double*) and asked it to take the value inside that box, multiply it with itself and put the result back in the same box. This is the mechanism of ‘Call by Reference’.
number to the function square(double*) and asked it to take the value inside that box, multiply it with itself and put the result back in the same box. This is the mechanism of ‘Call by Reference’.
Notice that there is no return
statement of square(double*) as we are putting the changed value (that could be
returned) inside the same memory location that was passed by the calling
function.
The output of the program will be as under:
The output of the program will be as under:
In
main(), before calling square(), x = 123.456
In main(), after calling square(), x = 15241.4
In main(), after calling square(), x = 15241.4
By and large, we try to avoid a call
by reference. Why? Mainly due to the side-effects, its use may cause. As
mentioned above, it will be risky to tell the address of some variables to the
called function. Also, see the code above for some special arrangements for
call by reference in C language. Only when extremely needed, like the size of
the data to be passed as value is huge or original variable is required to be
changed, you should go for call by reference, otherwise stick to the call by
value convention.
Lesson 13: Recursive Functions
This is the special type of function
which can call itself. What kind of function it would be? There are many
problems and specific areas where you can see the repetitive behavior (pattern)
or you can find a thing, which can be modeled in such a way that it repeats
itself.
Let us take a simple example of x10,
how will we calculate it? There are many ways of doing it. But from a simple
perspective, we can say that by definition:
x10= x * x9
So what is x9? It is x9
= x * x8 and so on.
We can see the pattern in it:
We can see the pattern in it:
xn = x * xn-1
To compute it, we can always write a
program to take the power of some number. How to do it? The power function
itself is making recursive call to itself. As a recursive function writer, you
should know where to stop the recursive call (base case). Like in this case,
you can stop when the power of x i.e. n is 1 or 0.
Similarly, you can see lot of
similar problems like Factorials. A factorial of a positive integer ‘n’ is
defined as:
n! = (n) * (n-1) * (n-2) * ….. * 2 *
1
Note that
n! = (n) * (n-1)! and
(n-1)! = (n-1) * (n-2)!
This is clearly a recursive
behavior. While writing a factorial function, we can stop recursive calling
when n is 2 or 1.
long fact(long n)
{
if (n <= 1)
return 1;
else
return n * fact(n-1);
}
{
if (n <= 1)
return 1;
else
return n * fact(n-1);
}
Note that there are two parts
(branches) of the function: one is the base case ( which indicates when the
function will terminate) and other is recursively calling part.
All the problems can be solved using
the iterative functions and constructs we have studied until now. So the
question is:
Do we need to use recursive
functions?
Yes, it adds little elegance to the
code of the function but there is a huge price to pay for this. Its use may
lead to the problems of having memory overhead. There may also be stacking
overhead as lots of function calls are made. A lot of functions can be written
without recursion (iteratively) and more efficiently.
So as a programmer, you have an
option to go for elegant code or efficient code, sometimes there is a
trade-off. As a general rule, when you have to make a choice out of elegance
and efficiency, where the price or resources is not an issue, go for elegance
but if the price is high enough then go for efficiency.
‘C’ language facilitates us for
recursive functions like lot of other languages but not all computer languages
support recursive functions. Also, all the problems can not be solved by
recursion but only those, which can be separated out for base case, not
iterative ones.
Lesson 14: Arrays
Our programming toolkit is almost
complete but still a very important component is missing. We are going to
discuss this component i.e. Arrays in this lesson. Array is a special
data-type. If we have a collection of data of same type like the ages of 100
students, arrays can be used. Arrays are data structure in which identical data
types are stored. In C language, every array has a data type i.e. name and
size. Data type can be any valid data type. The rules of variable naming
convention apply to array names. The size of the array tells how many elements
are there in the array. The size of the array should be a precise number. The
arrays occupy the memory depending upon their size and have contiguous area of
memory. We can access the arrays using the array index.
Declaration:
The declaration of arrays is as
follows:
data_type array_name [size] ;
for example:
int ages[10];
Let's consider an array int C[10];
This is an array of integer and has a name ’C'. It has a size ten which depicts
that the array ‘C’ can contain ten elements of int data type. In the memory,
the array occupies the contiguous area, in this case it will occupy forty bytes
(one int = 4 bytes). The elements of the array are manipulated using the index.
In C language, the index of array starts from zero and is one less than array's
size. Index of array is also called subscript.Arrays may be declared with
simple variables in a single line.
int i, age [10];
int height [10], length [10] ;
int height [10], length [10] ;
To access array, we can’t use the
whole array at a time. We access arrays element by element. An index
(subscript) may be used to access the first element of the array. In this case,
to access first element we write like age[0]. To access the 5th element, we
will write age[4] and so on. Using the index mechanism, we can use the array
elements as simple variables. We can use them anywhere, where we can use a
simple variable i.e. in assignment statements, expressions etc.
Initialization of Arrays
There are many ways to initialize an
array. Don't use the default initialization of arrays. Compiler may assign some
value to each declared array. Always initialize the array in such a manner that
the process is clear. We can initialize an array using a 'loop' while assigning
some value.
int i, age [10];
for ( i = 0; i < 10 ; i++ )
{
age[i] = 0;
}
for ( i = 0; i < 10 ; i++ )
{
age[i] = 0;
}
With the help of this simple loop,
we have initialized all the elements of array age to zero. In the loop
condition, we have used the condition i < 10, where the size of the array is
ten. As we know, the array index is one less than the size of the array. Here
we are using i as the index of array and its values are from 0 to 9. We can
also initialize the array at the time of declaration as:
int age [10] = { 0, 0, 0, 0, 0, 0,
0, 0, 0, 0 };
The above statement creates an array
age of integers and initializes all the elements with zero. We can use any
value to initialize the array by using any other number instead of zero.
However, generally, zero is used to initialize the integer variables. We can do
it by using the following shortcut.
int age [10] = { 0 };
The above statement has also
initialized all the elements of the array to zero. We have different ways of
initializing the arrays. Initialization through the use of loop is a better
choice. If the size of the array gets larger, it is tedious to initialize at
the declaration time. Consider the following statement:
int age [ ] = { 0, 0, 0, 0, 0, 0, 0,
0, 0, 0 };
Here we have not mentioned the size
of the array. The compiler is quite intelligent as it detects the
initialization list which consists of ten 0’s. Therefore, it creates an array
of 10 integers and initializes all the elements with zero. The index of the
arrays starts from the index 0 and is up to one less than the size of the
array. So if the size of the array is ten, the index will be from 0 to 9.
Similarly, if the size of the array is 253, the index will be from 0 to 252.
Lesson 15: Keyword Const and Arrays
|
To declare an array, we need its
data type, name and size. We use simple integer for the size like 10 or 100.
While using arrays in loops, we use the size a lot. Suppose if we have to
change the size of the array from 10 to 100, it will have to be changed at all
the places. Missing a place will lead to unexpected results. There is another
way to deal this situation i.e. keyword construct. The keyword const can be
used with any data type and is written before the data type as:
const int arraySize = 100;
This statement creates an identifier
arraySize and assigns it the value 100. Now the arraySize is called integer
constant. It is not a variable. We cannot change its value in the program. In
the array declaration, we can use this as:
int age [arraySize];
Now in the loop condition, we can
write like this:
for ( i = 0; i < arraySize ; i
++)
If we have to change the size of the
array, we only have to change the value of arraySize where it is declared. The
program will work fine in this case. This is a good programming practice to use
const for array size.
Sample Code:
Problem Statement:
Write a program which reads positive
integers from the user and stores these ones in an array. User can enter a
maximum of 100 numbers. Stop taking input when user enters -1.
Solution:
We have to declare an integer array
of size 100 to be used to store the integers. We used a loop to get the input
from the users. There are two conditions to terminate the loop i.e. either user
has entered 100 numbers or user entered -1. 'For' and 'while' loops can execute
zero or more times whereas ‘do-while’ may execute one or more times. By
analyzing the problem, the loop will be executed at least once so do-while loop
logically fits in this problem. We take an integer z to get the input from the
user and i as the counter so the condition will be as ( z != -1 && i
< 100 ). && is used to enforce that both the conditions are true. If
any of the two conditions becomes false, the loop will be terminated. The loop
counter is less than 100 because the index of the array will be from 0 to 99.
We will read a number from the user and store it at some particular location of
the array unless user enters -1 or 100 numbers are entered. In the loop, we
will use the if statement
whether the number entered by user is -1 or not. If the number entered is not -1, then we will store it in the array. The index of the array will also be incremented in each repetition. We can assign some value to array element as:
whether the number entered by user is -1 or not. If the number entered is not -1, then we will store it in the array. The index of the array will also be incremented in each repetition. We can assign some value to array element as:
c[ 3 ] = 33;
In an assignment statement, we
cannot use expression on the left hand side. Here c[3] is used as a variable
which represents the 4th element of the array. The complete code of the program
as under:
/* This program reads the input from
user and store it into an array and stop at -1.*/
#include <iostream.h>
main( )
{
#include <iostream.h>
main( )
{
const int arraySize = 100;
int c [ arraySize ] ;
int i, z;
do
{
int z , i = 0 ;
cout << “Please enter the number (-1 to end input) “ << endl;
cin >> z ;
if ( z != -1 )
{
c[ i ] = z ;
int c [ arraySize ] ;
int i, z;
do
{
int z , i = 0 ;
cout << “Please enter the number (-1 to end input) “ << endl;
cin >> z ;
if ( z != -1 )
{
c[ i ] = z ;
}
i ++ ;
} while ( z != -1 && i < arraySize ) ;
cout<<“The total number of positive integers entered by user is “<<i-1;
}
i ++ ;
} while ( z != -1 && i < arraySize ) ;
cout<<“The total number of positive integers entered by user is “<<i-1;
}
The above code shows that the
assignment statement of the array is inside the if block. Here the numbers will
be assigned to the array elements when the 'if statement' evaluates to true.
When the user enters -1, the if statement will evaluate it false. So the
assignment statement will not be executed and next i will be incremented. The
condition in the 'while loop' will be tested. As the value of z is -1, the loop
will be terminated. Now we have to calculate how many positive numbers, the
user has entered. In the end, we have incremented i so the actual positive
integers entered by the users is i -1. The above example is very useful in
terms of its practical usage. Suppose we have to calculate the ages of students
of the class. If we don’t know the exact number of students in the class, we
can declare an array of integers of larger size and get the ages from the user
and use -1 to end the input from the user.
A sample out put of the program is
as follow.
Please
enter the number (-1 to end input) 1
2
3
4
5
6
-1
The total number of positive integers entered by user is 6
2
3
4
5
6
-1
The total number of positive integers entered by user is 6
Lesson 16: Character Arrays
While dealing with words and
sentences, we actually make use of character arrays. Up to now, we were dealing
with integer arrays and storing integer values. Here we have to see what needs
to be done for storing a name. A simple variable can't be used to store a name
(which is a string of characters) as a variable stores only a single character.
We need a character array to grab a name. A character array is not different
from an integer array. To declare a character array, we will write as under:
char name [100] ;
In this way, we declare a string or
character array. There are some special properties of character arrays. Suppose
that we declare an array of 100 characters. We enter a name with 15-20
characters. These characters in the array occupy 15-20 character spaces. Now we
have to see what has happened to the remaining character spaces in the array.
Similarly, a question arises, will an array, displayed on the screen, show 100
characters with a name in 15-20 spaces and blanks for the remaining. Here C has
a character handling capability i.e. the notion of strings. When we place a
string in a character array, the computer keeps a mark to identify that the
array was of this size while the string stored in it is of the other size. That
marker is a special character, called null character. The ASCII code of null
character is all zeros. In C language, we represent the null character as “\0”.
C uses this character to terminate a string. All strings are terminated with
the null character.
We can store a string in a character
array named name simply by using the cin statement in the following way:
cin >> name ;
In the above statement, there is an
array on right hand side of cin instead of a simple variable. The cin stream
has a built-in intelligence that allows the compiler (program) to read whole
string at a time rather than a single character as in case of simple variable
of type char. The compiler determines that the name is not a simple variable.
Rather it is a string or character array. Thus cin reads a character array
until the user presses the enter key. When enter key is pressed, cin takes the
whole input (i.e. string) and stores it into the array name. The C language, by
itself, attaches a null character at the end of the string. In this way, the
total number of spaces occupied in the array by the string is the number of
characters entered by the user plus 1 (this one character is the null character
inserted at the end of the string by C automatically). The null character is
used to determine where the populated area of the array has ended. If we put a
string larger than the size of the array in absence of a null character in it,
then it is not possible to determine where a string is terminated in the
memory. This can cause severe logical error. So, one should be careful while
declaring a character array. The size of array should be one more than the
number of characters you want to store.
Initialization Of Character Arrays
We can initialize a character array
by giving a list of characters of the string.We write the characters of this
string one by one in single quotes (as we write a single character in single
quotes), separated by commas and enclosed in curly braces. So the
initialization line will be as under
char name [100] = {‘i’, ‘m’, ‘r’,
‘a’, ‘n’};
we can also write the string on
right hand side in double quotes as:
char name [100] = “imran” ;
The easy way to initialize a
character array is to assign it a string in double quotes. We can skip the size
of the array in the square brackets. We know that the compiler allocates the
memory at the declaration time, which is used during the execution of the
program. In this case, the compiler will allocate the memory to the array of
size equal to the number of characters in the provided string plus 1 (1 is for
the null character that is inserted at the end of string). Thus it is better to
initialize an array in the following way.
char name [] = “Hello World” ;
In the above statement, a memory of
12 characters will be allocated to the array name as there are 11 characters in
double quotes (space character after Hello is also considered and counted)
while the twelfth is the null character inserted automatically at the end of
the string.
We can do many interesting things
with arrays. Let’s start with reading a string (for example your name) from
keyboard and displaying it on the screen. For this purpose, we can write the
following code segment
char name [100] ;
cout << “Please enter your name : “ ;
cin >> name ;
cout << “Please enter your name : “ ;
cin >> name ;
In the cin statement, when the user
presses the enter key the previous characters entered, that is a string will be
stored in the array name. Now we have a string in the array name. We can
display it with cout statement. To display the string, we have stored in name.
We can write as under:
cout << name ;
This will display the string.
Alternatively, we can use a loop to display the string. As the string is an
array of characters, we can display these characters one by one in a 'for
loop'. We can write a loop as under
for ( i = 0 ; i < 100 ; i ++ )
cout << name [ i ] ;
cout << name [ i ] ;
Thus this loop will display the
characters in the array one by one in each iteration. First, it will display
the character at name [0], followed by that at name [1] and so on. Here we know
that the string in the array is terminated by a null character and after this
null character, there are random values that may not be characters (some
garbage data) in the array. We don’t want to display the garbage data that is
in the array after this null character. While using the statement cout <<
name; the cout stream takes the characters of the array name up to the null
character and the remaining part of the array is ignored. When we are
displaying the characters one by one, it is necessary to stop the displaying
process at the end of a string (which means when null character is reached).
For this purpose, we may put a condition in the loop to terminate the loop when
the null character is reached. So we can use if statement in the loop to check
the null character. We can modify the above for loop so that it could terminate
when null character reaches in the array.
for ( i = 0 ; i < 100 ; i ++ )
{ if (name [ i ] == ‘\0’)
break ;
cout << name [ i ] ;
}
{ if (name [ i ] == ‘\0’)
break ;
cout << name [ i ] ;
}
Lesson 17: Functions and Arrays
|
In C language, the default mechanism
of calling a function is ‘call by value’. When we call a function, say fn(),
and pass it a parameter x (argument value) by writing statement fn(x), the
calling mechanism puts the value of x at some other place. Then calls the
function and gives this value to it. This means a copy of the value is sent to
the program. The original x remains untouched and unchanged at its place. The
function uses the passed value (that has placed at some other place) and
manipulates it in its own way. When the control goes back to the calling
program, the value of original x is found intact. This is the call by value
mechanism.
Now let’s see what happens when we
pass an array to a function. To pass an array to a function, we will tell the
function two things about the array i.e. the name of the array and the size.
The size of the array is necessary to pass to the function. As the array is
declared in the calling function, it is visible there. The calling function
knows its size but the function being called does not know the size of the array.
So it is necessary to pass the size of the array along with its name. Suppose
we have declared a character array in the program by the following statement:
char name[50] ;
We have a function, say reverse that
reverses the array elements and displays them. Firstly, we need to write the
prototype of the function reverse. We say that this function returns nothing so
we use the keyword void in its return type. Secondly, we have to write the
parameters this function will get. We write these parameters with their type.
Now the prototype of this function will be written as
void reverse ( char [], int ) ;
In the above statement, the brackets
[] are necessary. These brackets indicate that an array of type char will be
passed to the function. If we skip these brackets and simply write char, it
will mean that a single character will be passed to the function. In addition,
the second parameter i.e. of type int, is of array's size. Note that in the
prototype of the function we have not written the names of the parameters. It
is not necessary to write the names of the parameters in function prototype.
However, if we write the names, it is not an error. The compiler will simply
ignore these names.
Now we will define the function reverse. In the function's definition, we will use the array and variable names. These names are local to this function so we can give these variables a name other than the one used in declaration in the calling program. We write this as below.
Now we will define the function reverse. In the function's definition, we will use the array and variable names. These names are local to this function so we can give these variables a name other than the one used in declaration in the calling program. We write this as below.
void reverse ( char characters [],
int arraySize )
{
// The body of the function.
}
{
// The body of the function.
}
You are encouraged to try to write
the function body for yourself.
Let’s say we have a character array
name and a name ‘adnan’ is stored in it. We call the reverse function by
passing the array name to it. For this we write
reverse ( name, 100 );
In this function call, we are
sending the name of the array to the function i.e. name and the size of the
array that is 100. When this call of the function is executed the control goes
to the function reverse. The statements in this function are executed which
reverses the array and displays it. After this, the control comes back to the
main function to the statement next to the function call statement. The return
type of the function is void so it does not return any thing. Now in the main,
we write the statement:
cout << name;
What will be displayed by this
statement? Whether it will be the original name ‘adnan’ or something else. It
will display the reversed array. In this instance, we see that whatever the
function reverse did to the array ( that was passed to it) is appearing in the
calling function. It means that the original array in the calling program has
been changed. Here we change (reverse) the order of the characters of array in
the function and find that the characters of the array in the calling function
are reversed. This means that the called function has not a copy of the array
but has the original array itself. Whereas in case of simple variables, a
called function uses a copy of variables passed to it in a 'call by value'
mechanism, which is by default in case of simple variables. In arrays, the by
default mechanism is ‘call by reference’. While passing arrays to a function,
we don’t need to use & and * operators, as we use for variables in call by
reference mechanism. Thus if we pass an array to a function, the array itself
is passed to the function. This is due to the fact that when we declare an
array, the name of the array has the address of the memory location from where
the array starts. In other words, it is the address of the first element of the
array. Thus the name of the array actually represents the address of the first
location of the array. Passing the name of array to a function means the
passing of the address of the array which is exactly the same as we do in call
by reference. So whatever the function does to the array, it is happening in
the same memory locations where the array originally resides. In this way, any
modifications that the function does to the contents of the array are taking
place in the contents of the original array too. This means that any change to
the array made by the function will be reflected in the calling program. Thus
an important point to remember is that whenever we pass simple variables to a
function, the default mechanism is call by value and whenever we pass an array
to a function, the default mechanism is call by reference. We know that when we
talk about a single element of an array like x [3] (which means the fourth
element of the array x), it is treated as simple variable. So if we pass a
single element of an array to a function (let’s say like fn ( x [3] ); ), it is
just like a simple variable whose copy is passed to the function (as it is a
call by value). The original value of the element in the array remains the
same. So be careful while passing arrays and a single element of array to
functions. This can be well understood from the following example.
Example Code
Suppose we declare an array in the
main program and pass this array to a function, which populates it with values.
After the function call, we display the elements of the array and see that it
contains the values that were given in the function call. This demonstrates
that the called function changes the original array passed to it. Following is
the code of the program.
/*This program demonstrates that
when an array is passed to a function then it is a call by reference and the
changes made by the function effects the original array*/
# include <iostream.h>
void getvalues( int [], int) ;
main ( )
{
int num [10], i ;
getvalues ( num, 10) ; //function call, passing array num
//display the values of the array
cout << “\n The array is populated with values \n” ;
for ( i = 0 ; i < 10 ; i ++)
cout << " num[" << i << "] = " << num[i]<< endl ;
}
void getvalues ( int num[], int arraysize)
{
int i ;
for ( i = 0 ; i < arraysize ; i ++)
num[i] = i ;
}
# include <iostream.h>
void getvalues( int [], int) ;
main ( )
{
int num [10], i ;
getvalues ( num, 10) ; //function call, passing array num
//display the values of the array
cout << “\n The array is populated with values \n” ;
for ( i = 0 ; i < 10 ; i ++)
cout << " num[" << i << "] = " << num[i]<< endl ;
}
void getvalues ( int num[], int arraysize)
{
int i ;
for ( i = 0 ; i < arraysize ; i ++)
num[i] = i ;
}
Here in the function getvalues, we
can get the values of the array from user by using the cin statement. Following
is the output of the execution of the program.
The
array is populated with values
num[0] = 0
num[1] = 1
num[2] = 2
num[3] = 3
num[4] = 4
num[5] = 5
num[6] = 6
num[7] = 7
num[8] = 8
num[9] = 9
num[0] = 0
num[1] = 1
num[2] = 2
num[3] = 3
num[4] = 4
num[5] = 5
num[6] = 6
num[7] = 7
num[8] = 8
num[9] = 9
Lesson 18: Multidimensional Arrays
There may be many applications of
arrays in daily life. In mathematics, there are many applications of arrays.
Let’s talk about vectors. A vector is a set of values which have independent
coordinates. There may be two-dimensional vector or three-dimensional vector.
There are dot and cross products of vectors besides many other manipulations.
We do all the manipulations using arrays. We manipulate the arrays with loops.
Then there is a mathematical structure matrix, which is in rows and columns.
These rows and columns are manipulated in two-dimensional arrays. To work with
rows and columns, C provides a structure i.e. a two-dimensional array. A two
dimensional array can be declared by putting two sets of brackets [] with the
name of array. The first bracket represents the number of rows while the second
one depicts the number of columns. So we can declare an array numbers of two
rows and three columns as follows.
int numbers [2] [3] ;
Using two-dimensional arrays, we can
do the addition, multiplication and other manipulations of matrices. A value in
a two-dimensional array is accessed by using the row number and column number.
To put values in a two-dimensional array is different from the one-dimensional
array. In one-dimensional array, we use a single 'for loop' to populate the
array while nested loops are used to populate the two-dimensional array. We can
do addition, multiplication and other manipulations of two-dimensional arrays.
In C language, we can declare arrays of any number of dimensions (i.e. 1, 2, 3
… n ). We declare a n-dimensional array by putting n pair of brackets [] after
the name of the array. So a three-dimensional array with values of dimensions
3, 5 and 7 respectively, will be declared as:
int num [3] [5] [7] ;
Example Code:
Let’s have a matrix (two-dimensional
array) of two rows and three columns. We want to fill it with values from the
user and to display them in two rows and three columns.
Solution
To solve this problem, we use a
two-dimensional array of two rows and three columns. First, we will declare the
array by writing
int matrix [2] [3] ;
We declare different variables in
our program. To put the values in the array, we use two nested for loops, which
can be written as under.
for ( row = 0 ; row < maxrows ;
row ++ )
{
for ( col = 0 ; col < maxcols ; col ++)
{
cout <<“Please enter a value for position[“ << row << “, ” << col << ”]” ;
cin >> matrix [row] [col] ;
}
}
{
for ( col = 0 ; col < maxcols ; col ++)
{
cout <<“Please enter a value for position[“ << row << “, ” << col << ”]” ;
cin >> matrix [row] [col] ;
}
}
The inner for loop totals the
elements of the array one row at a time. It fills all the columns of a row. The
outer for loop increments the row after each iteration. In the above code
segment, the inner loop executes for each iteration of the outer loop. Thus,
when the outer loop starts with the value of row 0, the inner loop is executed
for a number of iterations equal to the number of columns i.e. 3 in our
program. Thus the first row is completed for the three columns with positions
[0,0], [0,1] and [0,2]. Then the outer loop increments the row variable to 1
and the inner loop is again executed which completes the second row (i.e. the
positions [1,0], [1,1] and [1,2] ). All the values of matrix having two rows
and three columns are found. Similarly, to display these values one by one, we
again use nested loops. Following is the code of the program.
/*This program takes values from
user to fill a two-dimensional array (matrix) having two rows and three
columns. And then displays these values in row column format.*/
# include <iostream.h>
main ( )
{
int matrix [2] [3], row, col, maxrows = 2, maxcols = 3 ;
// get values for the matrix
for ( row = 0 ; row < maxrows ; row ++)
{
for (col = 0 ; col < maxcols ; col ++)
{
cout <<“Please enter a value for position[“<< row << “, ” << col << ”] ” ;
cin >> matrix [row] [col] ;
}
}
// Display the values of matrix
cout << “The values entered for the matrix are “ << endl ;
for ( row = 0 ; row < maxrows ; row ++)
{
for (col = 0 ; col < maxcols ; col ++)
{
cout << “\t” << matrix [row] [col] ;
}
cout << endl ; //to start a new line for the next row
}
}
main ( )
{
int matrix [2] [3], row, col, maxrows = 2, maxcols = 3 ;
// get values for the matrix
for ( row = 0 ; row < maxrows ; row ++)
{
for (col = 0 ; col < maxcols ; col ++)
{
cout <<“Please enter a value for position[“<< row << “, ” << col << ”] ” ;
cin >> matrix [row] [col] ;
}
}
// Display the values of matrix
cout << “The values entered for the matrix are “ << endl ;
for ( row = 0 ; row < maxrows ; row ++)
{
for (col = 0 ; col < maxcols ; col ++)
{
cout << “\t” << matrix [row] [col] ;
}
cout << endl ; //to start a new line for the next row
}
}
A sample output of the program is
given below.
Please enter a value for position [0,0] 1
Please enter a value for position [0,1] 2
Please enter a value for position [0,2] 3
Please enter a value for position [1,0] 4
Please enter a value for position [1,1] 5
Please enter a value for position [1,2] 6
The values entered for the matrix are
1 2 3
4 5 6
Please enter a value for position [0,1] 2
Please enter a value for position [0,2] 3
Please enter a value for position [1,0] 4
Please enter a value for position [1,1] 5
Please enter a value for position [1,2] 6
The values entered for the matrix are
1 2 3
4 5 6
Lesson 19: C Pointers
In the earlier lessons, we have
briefly referred to the concept of pointers. Let’s see what a pointer is and
how it can be useful. Pointers are a special type of variables in which a
memory address is stored. They contain a memory address, not the value of the
variable. The concept of the pointers can be well understood from the following
example.
Suppose, hundreds of people are
sitting in an auditorium. The host is going to announce a prize for
a person amongst the audience. There are two methods to call the prizewinner to stage. The host can either call the name of the person or the number of the seat. These are equivalent to ‘call by name’ and ‘call by address’ methods. In both cases, the prize will be delivered to a person whether he is called by name or referred by address (seat number in this case). In programming, pointers are used to refer by the addresses.
a person amongst the audience. There are two methods to call the prizewinner to stage. The host can either call the name of the person or the number of the seat. These are equivalent to ‘call by name’ and ‘call by address’ methods. In both cases, the prize will be delivered to a person whether he is called by name or referred by address (seat number in this case). In programming, pointers are used to refer by the addresses.
Declaration of Pointers
Pointers work by pointing to a
particular data type. We can have pointer to an integer, pointer to a double,
pointer to a character and so on. It means that a type is associated to a
pointer. Pointer, being a variable, needs a name. The rules for naming a
pointer are the same as for the simple variable names. The pointers are
declared in a specific way. The syntax of declaring a pointer is:
data type *name ;
Here ‘name’ is the name of the
pointer and data type is the type of the data to which the pointer (name)
points. There is no space between asterisk (*) and the name. Each variable
being declared as a pointer must be preceded by *. The * is associated with the
name of the variable, not with the data type. To associate the * (asterisk)
with data type (like int* ) may confuse the declaration statement. Suppose, we
want to declare a pointer to an integer. We will write as:
int *myptr;
Here myptr is the name of the
pointer. The easiest way to understand the pointer declaration line is the
reading the statement from right to left. For the above statement, we say that
myptr is a pointer to an integer (int). Similarly for the declaration double *x
, x is a pointer to a data of type double. The declaration of char *c shows
that c is a pointer to a data of type character. The declaration of multiple
pointers requires the use of * with each variable name. This is evident from the
following example which declares three pointers.
int *ptr1, *ptr2, *ptr3 ;
Moreover, we can mix the pointers
declaration with simple variables on one line.
int *ptr, x, a [10] ;
In this declaration ptr is a pointer
to data of type int, x is a simple variable of type int and a is an array of
integers. Whenever used, these pointers hold memory addresses. Now we will try
to understand what address a pointer holds. Suppose, we declare a pointer
variable ptr and a variable x and assign a value 10 to it. We write this as
under.
int *ptr ;
int x ;
x = 10 ;
int x ;
x = 10 ;
Here x is a name of a memory
location where a value 10 is stored. We want to store the address of this
memory location (which is labeled as x) into the pointer ptr. To get the
address of x, we use address operator i.e. &. (it is & not &&,
the && is logical AND). To assign the address of x to pointer ptr, we
write
ptr = &x ;
This statement assigns the memory
address of the location x to the pointer ptr.In the above assignment statement,
we have a pointer to a memory location. Now, it can be ascertained what value
is stored in that memory location. To get the value stored at a memory address,
we use the dereferencing operator, represented by asterisk (*). The * is used
with the name of the pointer to get the value stored at that address. To get
the value stored at the memory address ptr, we write *ptr which is read as the
value of whatever ptr points to. Thus the line z = *ptr; means, z has the value
of whatever ptr points to. We can use this operator (*) to get the value and
can do any arithmetic operation with it. The following statements make it
further clear.
z = *ptr + 2 ;
z = *ptr * 2 ;
z = *ptr – 2 ;
z = *ptr * 2 ;
z = *ptr – 2 ;
Here *ptr gives the value stored at
memory address where the pointer ptr points to.
Lesson 20: Pointers and Functions
In C language, the default mechanism
of function call is ‘call by value’. Sometimes we want to make a call by
reference. In call by reference, we pass the address of the variable to a
function by using & operator. One of the major usages of pointers is to
simulate call by reference while using it with
function calls. In the calling function, we pass the address of the variable to a function being called by using & operator. We write a function call as fn( &x ) where &x indicates that the address of variable x is being passed to the function fn. In the receiving function, the function must know that the parameter passed to it is an address. So the declaration of the receiving function will be as
function calls. In the calling function, we pass the address of the variable to a function being called by using & operator. We write a function call as fn( &x ) where &x indicates that the address of variable x is being passed to the function fn. In the receiving function, the function must know that the parameter passed to it is an address. So the declaration of the receiving function will be as
void fn ( int *num)
{
{
statement(s) ;
}
}
The int *num in the function
declaration indicates that the receiving variable is a pointer to a memory
address. In the body of the function, we will use this variable as:
cin >> *num ;
This statement describes that the
value entered through the keyboard (as cin is used) will be stored at the
memory address wherever the pointer num is pointing to. While using value
associated with the pointer, we write *num and &num in case of using the
address. This thing can be summarized as follows “*num means the value of whatever
the num points to and &num means the address of the variable num” The
pointers can appear on the left hand side exactly like ordinary variables. In
this case, you would have an address statement on the right hand side. The
address (operator (&) ) cannot be of an expression. Rather, it is always of
a simple variable. We cannot write &(x+y). The address (&) would be
either of x (&x) or of y (&y). The address operator (&) operates on
a simple variable. Precisely speaking, whenever we have a pointer on left hand
side, the right hand side should have an address. If a pointer appears on the
right hand side of an expression, it can participate in any expression. In this
case, we use the operator * with the pointer name and get the value stored
where the pointer points to. Obviously we can do any calculation with this
value (i.e. it can be used in any expression).
Constant Pointers:
Let’s look at the use of const with
pointers. Consider the following line of declaration:
int *const myptr = &x ;
The right hand side of this
assignment statement could be read as, myptr is a constant pointer to an
integer. Whenever we use the keyword const with a variable, the value of that
variable becomes constant and no other value can be assigned to it later on. We
know that when we declare a constant variable like const int x ; it is
necessary to assign a value to x and we write
const int x = 10;
After this, we cannot assign some
other value to x. The value of x can not be changed as it is declared as a
constant. Now consider the previous statement
int *const myptr = &x ;
Here we declare a constant pointer
to an integer. Being a constant pointer, it should immediately point to
something. Therefore, we assign this pointer an address of a variable x at the
time of declaration. Now this pointer cannot be changed. The pointer myptr will
hold the address of variable x throughout the program. This way, it becomes
just another name for the variable x.The use of keyword const in declaration
statement is a little tricky. The statement
int *const myptr = &x ;
means myptr is a constant pointer to
an integer. But if we change the place of const in this
statement and write
statement and write
const int *myptr = &x ;
This statement describes that myptr
is a pointer to a constant integer. This means that the value of pointer myptr
can be changed but the value stored at that location cannot be changed. This
declaration is useful. It has a common use in call by reference mechanism. When
we want to pass the arguments to a function by reference without changing the
values stored at that addresses. Then we use this construct of declaration
(i.e. const int *myptr) in the called function declaration. We write the
declaration of the function like
fn ( const int *myptr)
{
….
}
{
….
}
This declaration informs the
function that the receiving value is a constant integer. The function cannot
change this value. Thus we can use the address of that value for manipulations
but cannot change the value stored at that location.
Lesson 21: Pointers and Arrays
When we write int x, it means that
we have attached a symbolic name x, at some memory location. Now we can use x =
10 which replaces the value at that memory location with 10. Similarly while
talking about arrays, suppose an array as int y[10]. This means that we have
reserved memory spaces for ten integers and named it collectively as y. Now we
will see what actually y is? 'y' represents the memory address of the beginning
of this collective memory space. The first element of the array can be accessed
as y[0]. Remember arrays index starts from 0 in C language, so the memory
address of first element i.e. y[0] is stored in y.
“The name of the array is a constant
pointer which contains the memory address of the first element of the array”.
The difference between this and an
ordinary pointer is that the array name is a constant pointer. It means that
the array name will always point to the start of the array. In other words, it
always contains the memory address of the first element of the array and cannot
be reassigned any other address. Let's elaborate the point with the help of
following example.
int y[10];
int *yptr;
int *yptr;
In the above statements, we declare
an array y of ten integers and a pointer to an integer i.e. yptr. This pointer
may contain a memory address of an integer.
yptr = y;
This is an assignment statement. The
value of y i.e. the address of the first element of the array is assigned to
yptr. Now we have two things pointing to the same place, y and yptr. Both are
pointing to the first element of the array. However, y is a constant pointer
and always points to the same location whereas yptr is a pointer variable that
can also point to any other memory address.
Pointer Expressions and Arithmetic
Suppose we have an array y and yptr,
a pointer to array. We can manipulate arrays with both y and yptr. To access
the fourth element of the array using y, we can say y[3];
with yptr, we can write as *(yptr
+ 3). Now we have to see what happens
when we increment or add something to a pointer. We know that y is a constant
pointer and it can not be incremented. We can write y[0], y[1] etc. On the
other hand, yptr is a pointer variable and can be written as the statement yptr
= y. It means that yptr contains the address of the first element of the array.
However, when we say yptr++, the value of yptr is incremented. But how much? To
explain it further, we increment a normal integer variable like x++. If x
contains 10, it will be incremented by 1 and become 11. The increment of a
pointer depends on its data type. The data type, the pointer points to, determines
the amount of increment. In this case, yptr is an integer pointer. Therefore,
when we increment the yptr, it points to the next integer in the memory. If an
integer occupies four bytes in the memory, then the yptr++; will increment its
value by four. This can be understood from the following example.
/* This program will print the
memory address of a pointer and its incremented address.*/
#include<iostream.h>
main()
{
int y[10]; // an array of 10 integers
int *yptr; // an integer pointer
yptr = y; // assigning the start of array address to pointer
#include<iostream.h>
main()
{
int y[10]; // an array of 10 integers
int *yptr; // an integer pointer
yptr = y; // assigning the start of array address to pointer
// printing the memory address
cout << “The memory address of yptr = “ << yptr << endl ;
yptr++; // incrementing the pointer
// printing the incremented memory address
cout << “The memory address after incrementing yptr = ” << yptr << endl;
}
cout << “The memory address of yptr = “ << yptr << endl ;
yptr++; // incrementing the pointer
// printing the incremented memory address
cout << “The memory address after incrementing yptr = ” << yptr << endl;
}
In the above program, the statement
cout << yptr will show the memory address the yptr points to. You will
notice the difference between the two printed addresses. By default, the memory
address is printed in hexadecimal by the C output system. Therefore, the
printed address will be in hexadecimal notation. The difference between the two
addresses will be four as integer occupies four bytes and yptr is a pointer to
an integer. “When a pointer is incremented, it actually jumps the number of
memory spaces according to the data type that it points to”.
The
sample out put of the program is:
The memory address of yptr = 0x22ff50
The memory address after incrementing yptr = 0x22ff54
The memory address of yptr = 0x22ff50
The memory address after incrementing yptr = 0x22ff54
yptr which was pointing to the start
of the array y, starts pointing to the next integer in memory after
incrementing it. In other words, yptr is pointing to the 2nd element of the
array. On being incremented again, the yptr will be pointing to the next
element of the array i.e. y[2], and so on. We know that & is address
operator which can be used to get the memory address. Therefore, we can also
get the address of the first element of the array in yptr as:
yptr = &y[0] ;
y[0] is a single element and its
address can be got with the use of. the address operator (&). Similarly we
can get the address of 2nd or 3rd element as &y[1], &y[2] respectfully.
We can get the address of any array element and assign it to yptr. Suppose the
yptr is pointing to the first element of the array y. What will happen if we
increment it too much? Say, the array size is 10. Can we increment the yptr up
to 12 times? And what will happen? Obviously, we can increment it up to 12
times. In this case, yptr will be pointing to some memory location containing
garbage (i.e. there may be some value but is useless for us).
Here is an example describing
different methods to access array elements.
/* This program contains different
ways to access array elements */
#include <iostream.h>
main ()
{
int y[10] = {0,5,10,15,20,25,30,35,40,45};
int *yptr;
yptr = y; // Assigning the address of first element of array.
cout << “Accessing 6th element of array as y[5] = ” << y[5] << endl;
cout << “Accessing 6th element of array as *(yptr + 5) = ” << *(yptr + 5) << endl;
cout << “Accessing 6th element of array as yptr[5] = “ << yptr[5] << endl;
}
The output of the program is:
Accessing 6th element of array as y[5] = 25
Accessing 6th element of array as *(yptr + 5) = 25
Accessing 6th element of array as yptr[5] = 25
#include <iostream.h>
main ()
{
int y[10] = {0,5,10,15,20,25,30,35,40,45};
int *yptr;
yptr = y; // Assigning the address of first element of array.
cout << “Accessing 6th element of array as y[5] = ” << y[5] << endl;
cout << “Accessing 6th element of array as *(yptr + 5) = ” << *(yptr + 5) << endl;
cout << “Accessing 6th element of array as yptr[5] = “ << yptr[5] << endl;
}
The output of the program is:
Accessing 6th element of array as y[5] = 25
Accessing 6th element of array as *(yptr + 5) = 25
Accessing 6th element of array as yptr[5] = 25
In the above example, there are two
new expressions i.e. *(yptr+5) and yptr[5]. In the statement *(yptr+5), yptr is
incremented first by 5 (parenthesis are must here). Resultantly, it points to
the 6th element of the array. The dereference pointer gives the value at that
address. As yptr is a pointer to an integer, so it can be used as array name.
So the expression yptr[5] gives us the 6th element of the array.
Lesson 22: Pointer Comparison
|
We have seen pointers in different
expressions and arithmetic operations. Can we compare pointers? Yes, two
pointers can be compared. Pointers can be used in conditional statements as
usual variables. All the comparison operators can be used with pointers i.e.
less than, greater than, equal to, etc. Suppose in sorting an array we are
usingtwo pointers. To test which pointer is at higher address, we can compare
them and take decision depending on the result.
Again consider the two pointers to
integer i.e. yptr1 and yptr2. Can we compare *yptr1 and *yptr2? Obviously
*yptr1 and *yptr2 are simple values. It is the value of integer yptr1, yptr2
points to. When we say *yptr1 > *yptr2, this is a comparison of simple two
integer values. Whenever we are using the dereference pointer (pointers with
*), all normal arithmetic and manipulation is valid. Whenever we are using
pointers themselves, then certain type of operations are allowed and
restrictions on other.Consider a sample program as follows:
/* Program using the dereference
pointer comparison */
#include <iostream.h>
main ()
{
int x, y, *xptr, *yptr;
cout << “ \n Please enter the value of x = “ ;
cin >> x ;
cout << “ \n Please enter the value of y = “;
cin >> y ;
xptr = &x;
yptr = &y;
if (*xptr > *yptr )
{
cout << “ \n x is greater than y “;
}
else
{
cout << “\n y is greater than x “;
}
}
#include <iostream.h>
main ()
{
int x, y, *xptr, *yptr;
cout << “ \n Please enter the value of x = “ ;
cin >> x ;
cout << “ \n Please enter the value of y = “;
cin >> y ;
xptr = &x;
yptr = &y;
if (*xptr > *yptr )
{
cout << “ \n x is greater than y “;
}
else
{
cout << “\n y is greater than x “;
}
}
The output of the program is;
Please enter the value of x = 6
Please enter the value of y = 9
is greater than x
Please enter the value of x = 6
Please enter the value of y = 9
is greater than x
More on Pointer Arithmetic
Pointers are associated to some data
type as pointer to integer, pointer to float and pointer to char etc. When a
pointer is incremented or decremented, it changes the address by the number of
bytes occupied by the data type that the pointer points to.
For example, if we have a pointer to
an integer, by incrementing the pointer the address will be incremented by four
bytes, provided the integer occupies four bytes on that machine. If it is a
pointer to float and float occupies eight bytes, then by incrementing this
pointer, its address will be incremented by eight bytes. Similarly, in case of
a pointer to a char, which normally takes one byte, incrementing a pointer to
char will change the address by one.We have seen that we can do different
arithmetic operations with pointers. Let's see can two pointers be added?
Suppose we have two pointers yptr1 and yptr2 to integer and
written as
written as
yptr1 + yptr2 ;
The compiler will show an error in
this statement. Think logically what we can obtain by adding the two memory
addresses. Therefore, normally compiler will not allow this operation. Can we
subtract the pointers? Yes, we can. Suppose we have two pointers pointing to
the same memory address. When we subtract these, the answer will be zero.
Similarly, if a pointer is pointing to the first element of an integer array
while another pointer pointing to the second element of the array. We can
subtract the first pointer from second one. Here the answer will be one, i.e.
how many array elements are these two pointers apart.
Lesson 23: Pointers, Strings and Arrays
|
We have four basic data types i.e.
char, int, float and double. Character strings are arrays of characters.
Suppose, there is a word or name like Amir to store in one entity. We cannot
store it into a char variable because it can store only one character. For this
purpose, a character array is used. We can write it as:
char name [20];
We have declared an array name of 20
characters .It can be initialized as:
name[0] = ‘A’ ;
name[1] = ‘m’ ;
name[2] = ‘i’ ;
name[3] = ‘r’ ;
name[1] = ‘m’ ;
name[2] = ‘i’ ;
name[3] = ‘r’ ;
Each array element is initialized
with a single character enclosed in single quote. We cannot use more than one
character in single quotes, as it is a syntax error. Is the initialization of
the array complete? No, the character strings are always terminated by null
character ‘\0’. Therefore, we have to put the null character in the end of the
array.
name[4] = ‘\0’ ;
Here we are using two characters in
single quotes. But it is a special case. Whenever back slash ( \ ) is used, the
compiler considers both the characters as single (also known as escape
characters). So ‘\n’ is new line character, ‘\t’ a tab character and ‘\0’ a
null character. All of these are considered as single characters. What is the
benefit of having this null character at the end of the string? Write a
program, do not use the null character in the string and try to print the
character array using cout and see what happens? cout uses the null character
as the string terminating point. So if cout does not find the null character it
will keep on printing. Remember, if we want to store fifteen characters in an
array, the array size should be at least sixteen i.e. fifteen for the data and
one for the null character. Do we always need to write the null character at
the end of the char array by ourselves? Not always, there is a short hand
provided in C, i.e. while declaring we can initialize the arrays as:
char name[20] = “Amir”;
When we use double quotes to
initialize the character array, the compiler appends null character at the end
of the string.“Arrays must be at least one character space larger than the
number of printable characters which are to be stored”.
Example Code:
/* This program copies a character
array into a given array */
#include <iostream.h>
main( )
{
char strA[80] = "A test string";
char strB[80];
char *ptrA; /* a pointer to type character */
char *ptrB; /* another pointer to type character */
ptrA = strA; /* point ptrA at string A */
ptrB = strB; /* point ptrB at string B */
while(*ptrA != '\0')
{
*ptrB++ = *ptrA++; // copying character by character
}
*ptrB = '\0';
cout << “String in strA = ” << strA << endl; /* show strA on screen */
cout << “String in strB = ” << strB << endl; /* show strB on screen */
}
#include <iostream.h>
main( )
{
char strA[80] = "A test string";
char strB[80];
char *ptrA; /* a pointer to type character */
char *ptrB; /* another pointer to type character */
ptrA = strA; /* point ptrA at string A */
ptrB = strB; /* point ptrB at string B */
while(*ptrA != '\0')
{
*ptrB++ = *ptrA++; // copying character by character
}
*ptrB = '\0';
cout << “String in strA = ” << strA << endl; /* show strA on screen */
cout << “String in strB = ” << strB << endl; /* show strB on screen */
}
The output of the program is:
String in strA = A test string
String in strB = A test string
String in strA = A test string
String in strB = A test string
Explanation:
We have declared a char array named
strA of size 80 and initialized it with some value say “A test String” using
the double quotes. Here we don’t need to put a null character. The compiler
will automatically insert it. But while declaring another array strB of the
same size, we declare two char pointers *ptrA and *ptrB. The objective of this
exercise is to copy one array into another array. We have assigned the starting
address of array strA to ptrA and strB to ptrB. Now we have to run a loop to
copy all the characters from one array to other. To terminate the loop, we have
to know about the actual number of characters or have to use the string
termination character. As we know, null character is used to terminate a
string, so we are using the condition in 'while loop' as: *ptrA != ‘\0’ ,
simply checking that whatever ptrA is pointing to is not equal to ‘\0’. Look at
the statement *ptrB++ = *ptrA++. What has happened in this statement? First of
all, whatever ptrA is pointing to will be assigned to the location where ptrB
is pointing to. When the loop starts, these pointers are pointing to the start
of the array. So the first character of strA will be copied to the first
character of strB. Afterwards, the pointers will be incremented, not the values
they are pointing to. Therefore, ptrA is pointing to the 2nd element of the
array strA and ptrB is pointing to the 2nd element of the array strB. In the
2nd repetition, the loop condition will be tested. If ptrA is not pointing to a
null character the assignment for the 2nd element of the array takes place and
so on till the null character is reached. So all the characters of array strA
are copied to array strB. Is this program complete? No, the array strB is not
containing the null character at the end of the string. Therefore, we have
explicitly assigned the null character to strB. Do we need to increment the
array pointer? No, simply due to the fact that in the assignment statement ( *ptrA++
= *ptrB++;), the pointers are incremented after the assignment. This program
now successfully copies one string to other using only pointers.
To further understand pointers,
let's consider the following statement.
char myName[] = "Full
Name";
This statement creates a 'char' type
array and populates it with a string. Remember the character strings are null (
'\0' ) terminated. We can achieve the same thing with the use of pointer as
under:
char * myNamePtr = "Full
Name";
When we create an array, the array
name, 'myName' in this case, is a constant pointer. The starting address of the
memory allocated to string "FullName" becomes the contents of the
array name 'myName' and the array name 'myName' can not be assigned any other
value. In other words, the location to which array names points to can not be
changed. In the second statement, the 'myNamePtr' is a pointer to a string
"FullName", which can always be changed to point to some other
string.
Lesson 24: Pointers and Multidimensional Arrays
Now we will see what is the
relationship between the name of the array and the pointer. Suppose we have a
two-dimensional array:
char multi[5][10];
In the above statement, we have
declared a 'char' type array of 5 rows and 10 columns.
A multi-dimensional array is stored
in the memory in a series i.e. the elements of first row and first column and
then the elements of the second row and coloumn and so on.
As discussed above, the array name
points to the starting memory location of the memory allocated for the array
elements. Here the question arises where the 'multi' will be pointing if we add
1 to ‘multi’. We know that a pointer is incremented by its type number of
bytes. In this case, 'multi' is an array of 'char' type that takes 1 byte. Therefore,
‘muti+1’ should take us to the second element of the first row (row 0). But
this time, it is behaving differently. It is pointing to the first element (col
0) of the second row (row 1). So by adding '1' in the array name, it has jumped
the whole row or jumped over as many memory locations as number of columns in
the array. The width of the columns depends upon the type of the data inside
columns. Here, the data type is 'char', which is of 1 byte. As the number of
columns for this array 'multi' is 10, it has jumped 10 bytes.
Remember, whenever some number is
added in an array name, it will jump as many rows as the added number. If we
want to go to the second row (row 1) and third column (col 2) using the same
technique, it is given ahead but it is not as that straight forward.
Remember, if the array is to be
accessed in random order, then the pointer approach may not be better than
array indexing. We already know how to dereference array elements using
indexing. So the element at second row and third column can be accessed as
'multi[1][2]'. To do dereferencing using pointers we use '*' operator.
In case of one-dimensional array,
'*multi' means 'the value at the address, pointed to by the name of the array'.
But for twodimensional array '*multi' still contains an address of the first
element of the first row of the array or starting address of the array 'multi'.
See the code snippet to prove it.
/* This program uses the
multi-dimensional array name as pointer */
#include <iostream.h>
void main(void)
{
//To avoid any confusion, we have used ‘int’ type below
int multi[5][10];
cout << "\n The value of multi is: " << multi;
cout << "\n The value of *multi is: " << *multi;
}
void main(void)
{
//To avoid any confusion, we have used ‘int’ type below
int multi[5][10];
cout << "\n The value of multi is: " << multi;
cout << "\n The value of *multi is: " << *multi;
}
Now, look at the output below:
The
value of multi is: 0x22feb0
The value of *multi is: 0x22feb0
The value of *multi is: 0x22feb0
It is pertinent to note that in the
above code, the array ‘multi’ has been changed to ‘int’ from ‘char’ type to
avoid any confusion.
To access the elements of the
two-dimensional array, we do double dereferencing like '**multi'. If we want to
go to, say, 4th row (row 3), it is achieved as 'multi + 3' . Once reached in
the desired row, we can dereference to go to the desired column. Let's say we
want to go to the 4th column. It can be done in the following manner.
*(*(multi+3)+3);
Lesson 25: Pointers to Pointers
What we have been talking about, now
we will introduce a new terminology, is actually a case of ‘Pointer to
Pointer’. We were doing double dereferencing to access the elements of a
two-dimensional array by using array name (a pointer) to access a row (another
pointer) and further to access a column element (of ‘int’ data type). In case
of single dereference, the value of the pointer is the address of the variable
that contains the value desired. In the case of pointer to pointer or double
dereference, the first pointer contains the address of the second pointer,
which contains the address of the variable, which contains the desired value.
Pointers to Pointers are very useful. But you need to be very careful while
using the technique to avoid any problem.
We can also declare an array of
pointers. An array of pointers is used to store pointers in it. Now we will try
to understand how do we declare an array of pointers. The following statement
can help us in comprehending it properly.
char * myarray[10];
We read it as: ‘myarray is an array
of 10 pointers to character’.
Command Line Arguments
Until now, we have always written
the ‘main()’ function as under:
main( )
{
. . . // code statements
}
{
. . . // code statements
}
But we are now in a position to
write something inside the parenthesis of the ‘main()’ function. In C language,
whenever a program is executed, the user can provide the command-line arguments
to it like:
C:\Dev-cpp\work>Program-name
argument1 argument2 ……argumentN
We have so far been taking input
using the ‘cout’ and ‘cin’ in the program. But now we can also pass arguments
from the command line just before executing the program. For this purpose, we
will need a mechanism. In C, this can be done by using ‘argc’ and ‘argv’
arguments inside the main( ) function as:
void main(int argc, char **argv)
{
. . .
}
{
. . .
}
Note that ‘argc’ and ‘argv’ are
conventional names of the command line parameters of the ‘main()’ function.
However, you can give the desired names to them.
argc = Number of command line
arguments. Its type is ‘int’.
argv = It is a pointer to an array
of character strings that contain the arguments, one per string. ‘**argv’ can
be read as pointer to pointer to char.
Now the command line arguments can
be accessed from inside the program using ‘argc’ and ‘argv’ variables. It will
be an interesting experience for you to try out the following code:
/* Accessing the command line
arguments */
#include <iostream.h>
main(int argc, char **argv)
{
cout << argc << endl;
cout << *argv;
}
#include <iostream.h>
main(int argc, char **argv)
{
cout << argc << endl;
cout << *argv;
}
If we run this program without any
argument, then what should be the answer. It will be not correct to think that
the argc (number of arguments) is zero as we have not passed any argument. It
counts program name as the first argument. So programs written in C/C++ know
their names supplied in the first command-line argument. By running the above
program, we can have the following output:
c:\dev-cpp\work>program
1
program
1
program
Here we see that the number of
arguments is 1 with the first argument as the program name itself. You have to
go to the command prompt to provide the command line arguments.
The command line arguments are
separated by spaces. You can provide command line arguments to a program as
under:
c:\dev-cpp\work>program
1 2
Here the number of arguments (argc)
will be 3. The argument “1” and “2” are available inside the program as
character strings.
Lesson 26: String Manipulation
C language provides many functions
to manipulate strings. To understand the functions, let’s consider building
block (or unit) of a string i.e., a character. Characters are represented
inside the computers in terms of numbers. There is a code number for each
character, used by a computer. Mostly the computers use ASCII (American
Standard Code for Information Interchange) code for a character to store it.
This is used in the computer memory for manipulation. It is used as an output
in the form of character. We can write a program to see the ASCII values. We
have a data type char to store a character. A character includes every thing,
which we can type with a keyboard for example white space, comma, full stop and
colon etc all are characters. 0, 1, 2 are also characters. Though, as numbers,
they are treated differently, yet they are typed as characters. Another data
type is called as int, which stores whole numbers. As we know that characters
are stored inside computer as numbers so these can be manipulated in the same
form. A character is stored in the memory in one byte i.e. 8 bits. It means
that 28 (256) different combinations for different values can be stored. We
want to ascertain what number it stores, when we press a key on the board. In
other words, we will see what character will be displayed when we have a number
in memory. The code of the program, which displays the characters and their
corresponding integer, values (ASCII codes) is as under.
In the program the statement c = i ;
has integer value on right hand side (as i is an int) while c has its character
representation. We display the value of i and c. It shows us the characters and
their integer values.
//This program displays the ASCII
code table
# include <iostream.h>
main ( )
{
# include <iostream.h>
main ( )
{
int i, char c ;
for (i = 0 ; i < 256 ; i ++)
{
c = i ;
cout << i << “\t” << c << “\n” ;
}
}
for (i = 0 ; i < 256 ; i ++)
{
c = i ;
cout << i << “\t” << c << “\n” ;
}
}
In the output of this program, we
will see integer numbers and their character representation. For example, there
is a character, say white space (which we use between two words). It is a
non-printable character and leaves a space. From the ASCII table, we can see
that the values of a-z and A-Z are continuos. We can get the value of an
alphabet letter by adding 1 to the value of its previous letter. So what we
need to remember as a baseline is the value of ‘a’ and ‘A’.
Character Handling Functions
C language provides many functions
to perform useful tests and manipulations of character data. These functions
are found in the header file ctype.h. The programs that have character
manipulation or tests on character data must have included this header file to
avoid a compiler error. Each function in ctype.h receives a character (an int )
or EOF (end of file; it is a special character) as an argument. ctype.h has
many functions, which have self-explanatory names. Of these, int isdigit (int
c) takes a simple character as its argument and returns true or false. This
function is like a question being asked. The question can be described whether
it is a character digit? The answer may be true or false. If the argument is a
numeric character (digit), then this function will return true otherwise false.
This is a useful function to test the input. To check for an alphabet (i.e.
a-z), the function isalpha can be used. isalpha will return true for alphabet
a-z for small and capital letters. Other than
alphabets, it will return false. The function isalnum (is alphanumeric) returns true if its argument is a digit or letter. It will return false otherwise. All the functions included in ctype.h are shown below with their description.
alphabets, it will return false. The function isalnum (is alphanumeric) returns true if its argument is a digit or letter. It will return false otherwise. All the functions included in ctype.h are shown below with their description.
Prototype
|
Description
|
int isdigit( int c )
|
Returns true if c is a digit and
false otherwise.
|
int isalpha( int c )
|
Returns true if c is a letter and
false otherwise.
|
int isalnum( int c )
|
Returns true if c is a digit or a
letter and false otherwise.
|
int isxdigit( int c
)
|
Returns true if c is a hexadecimal
digit character and false otherwise.
|
int islower( int c )
|
Returns true if c is a lowercase
letter and false otherwise.
|
int isupper( int c )
|
Returns true if c is an uppercase
letter; false otherwise.
|
int tolower( int c )
|
If c is an uppercase letter,
tolower returns c as a lowercase letter. Otherwise, tolower returns the
argument unchanged.
|
int toupper( int c )
|
If c is a lowercase letter,
toupper returns c as an uppercase letter. Otherwise, toupper returns the
argument unchanged.
|
int isspace( int c )
|
Returns true if c is a white-space
character—newline ('\n'), space (' '), form feed ('\f'), carriage return
('\r'), horizontal tab ('\t'), or vertical tab ('\v')—and false otherwise
|
int iscntrl( int c )
|
Returns true if c is a control
character and false otherwise.
|
int ispunct( int c )
|
Returns true if c is a printing
character other than a space, a digit, or a letter and false otherwise.
|
int isprint( int c )
|
Returns true value if c is a
printing character including space (' ') and false otherwise.
|
int isgraph( int c )
|
Returns true if c is a printing
character other than space (' ') and false otherwise.
|
The functions tolower and toupper
are conversion functions. The tolower function converts its uppercase letter
argument into a lowercase letter. If its argument is other than uppercase
letter, it returns the argument unchanged. Similarly the toupper function
converts its lowercase letter argument into uppercase letter. If its argument
is other than lowercase letter, it returns the argument without effecting any
change.
Lesson 27. Character
Handling Functions
Let’s consider the following example
to further demonstrate the use of the functions of ctype.h. Suppose, we write a
program which prompts the user to enter a string. Then the string entered is
checked to count different types of characters (digit, upper and lowercase
letters, white space etc). We keep a counter for each category of character
entered. When the user ends the input, the number of characters entered in different
types will be displayed. In this example we are using a function getchar(),
instead of cin to get the input. This function is defined in header file as
stdio.h. While carrying out character manipulation, we use the getchar()
function. This function reads a single character from the input buffer or
keyboard. This function can get the new line character ‘\n’ (the ENTER key) so
we run the loop for input until user presses the ENTER key. As soon as the
getchar() gets the ENTER key pressed (i.e. new line character ‘\n’), the loop
is terminated. We know that, every C statement returns a value. When we use an
assignment statement ( as used in our program c = getchar()), the value
assigned to the left hand side variable is the value of the statement too. Thus,
the statement (c = getchar()) returns the value that is assigned to char c.
Afterwards, this value is compared with the new line character ‘\n’. If it is
not equal inside the loop, we apply thetests on c to check whether it is
uppercase letter, lowercase letter or a digit etc. In this program, the whole
string entered by the user is manipulated character by character.
Following is the code of this
program.
// Example: analysis of text using
<ctype.h> library
#include <iostream.h>
#include <stdio.h>
#include <ctype.h>
main()
{
char c;
int i = 0, lc = 0, uc = 0, dig = 0, ws = 0, pun = 0, oth = 0;
cout << "Please enter a character string and then press ENTER: ";
// Analyse text as it is input:
while ((c = getchar()) != '\n')
{
if (islower(c))
lc++;
else if (isupper(c))
uc++;
else if (isdigit(c))
dig++;
else if (isspace(c))
ws++;
else if (ispunct(c))
pun++;
else
oth++;
}
// display the counts of different types of characters
cout << "You typed:"<< endl;
cout<< "lower case letters = "<< lc<< endl;
cout << "upper case letters = " << uc <<endl;
cout<< "digits = " << dig << endl;
cout<< "white space = "<< ws << endl;
cout<< "punctuation = "<< pun<< endl;
cout<< "others = "<< oth;
}
#include <iostream.h>
#include <stdio.h>
#include <ctype.h>
main()
{
char c;
int i = 0, lc = 0, uc = 0, dig = 0, ws = 0, pun = 0, oth = 0;
cout << "Please enter a character string and then press ENTER: ";
// Analyse text as it is input:
while ((c = getchar()) != '\n')
{
if (islower(c))
lc++;
else if (isupper(c))
uc++;
else if (isdigit(c))
dig++;
else if (isspace(c))
ws++;
else if (ispunct(c))
pun++;
else
oth++;
}
// display the counts of different types of characters
cout << "You typed:"<< endl;
cout<< "lower case letters = "<< lc<< endl;
cout << "upper case letters = " << uc <<endl;
cout<< "digits = " << dig << endl;
cout<< "white space = "<< ws << endl;
cout<< "punctuation = "<< pun<< endl;
cout<< "others = "<< oth;
}
A sample output of the program is
given below.
Please
enter a character string and then press ENTER: Sixty Five = 65.00
You typed:
lower case letters = 7
upper case letters = 2
digits = 4
white space = 3
punctuation = 2
others = 0
You typed:
lower case letters = 7
upper case letters = 2
digits = 4
white space = 3
punctuation = 2
others = 0
Lesson 28: String Conversion Functions
|
The header file stdlib.h includes
functions, used for different conversions.
When we get input of a different
type other than the type of variable in which the value is being stored, it
warrants the need to convert that type into another type.
These conversion functions take an
argument of a type and return it after converting into another type. These
functions and their description are given in the table below.
Prototype
|
Description
|
double atof( const
char *nPtr )
|
Converts the string nPtr to
double.
|
Int atoi( const char
*nPtr )
|
Converts the string nPtr to int.
|
long atol( const
char *nPtr )
|
Converts the string nPtr to long
int.
|
double strtod( const
char *nPtr, char **endPtr )
|
Converts the string nPtr to
double.
|
long strtol( const
char *nPtr, char **endPtr, int base )
|
Converts the string nPtr to long.
|
unsigned long
strtoul( const char *nPtr, char **endPtr, int base )
|
Converts the string nPtr to
unsigned long.
|
Use of String Conversion functions:
While writing main () in a program,
we can put them inside the parentheses of main. ‘int arg c, char ** arg v are
written inside the parentheses. The arg c is the count of number of arguments
passed to the program including the name of the program itself while arg v is a
vector of strings or an array of strings. It is used while giving command line
arguments to the program.
The arguments in the command line
will always be character strings. The number in the command line (for example
12.8 or 45) are stored as strings. While using the numbers in the program, we
need these conversion functions.
Following is a simple program which
demonstrate the use of atoi function. This program prompts the user to enter an
integer between 10-100, and checks if a valid integer is entered.
//This program demonstrate the use of
atoi function
# include <iostream.h>
# include <stdlib.h>
# include <stdlib.h>
main( )
{
{
int anInteger;
char myInt [20]
cout << "Enter an integer between 10-100 : ";
cin >> myInt;
char myInt [20]
cout << "Enter an integer between 10-100 : ";
cin >> myInt;
if (atoi(myInt) == 0)
cout << "\nError : Not a valid input"; // could be non numeric
else
{
anInteger = atoi(myInt);
if (anInteger < 10 || anInteger > 100)
cout << "\nError : only integers between 10-100 are allowed!";
else
cout << "\n OK, you have entered " << anInteger;
}
}
cout << "\nError : Not a valid input"; // could be non numeric
else
{
anInteger = atoi(myInt);
if (anInteger < 10 || anInteger > 100)
cout << "\nError : only integers between 10-100 are allowed!";
else
cout << "\n OK, you have entered " << anInteger;
}
}
The output of the program is as
follows.
Enter
an integer between 10-100 : 45.5
OK, you have entered 45
OK, you have entered 45
Lesson 29: String Functions
C library provides many functin to
manipulat string. Like functions to compare strings, copy a string and so on.
Below is a list of the string manipulation functions and their description. All these functions are defined in the header file string.h, in the C library. Example code is also part of this lesson.
Below is a list of the string manipulation functions and their description. All these functions are defined in the header file string.h, in the C library. Example code is also part of this lesson.
Function Prototype
|
Function description
|
char *strcpy( char
*s1, const char *s2 )
|
Copies string s2 into character
array s1. The value of s1 is returned.
|
char *strncpy( char
*s1, const char *s2, size_t n )
|
Copies at most n characters of
string s2 into array s1. The value of s1 is returned.
|
char *strcat( char
*s1, const char *s2 )
|
Appends string s2 to array s1. The
first character of s2 overwrites the terminating null character of s1. The
value of s1 is returned.
|
char *strncat( char
*s1, const char *s2, size_t n )
|
Appends at most n characters of
string
s2 to array s1. The first character of s2 overwrites the terminating null character of s1. The value of s1 is returned. |
int strcmp( const
char *s1, const char *s2)
|
Compares string s1 to s2. Returns
a
negative number if s1 < s2, zero if s1 == s2 or a positive number if s1 > s2 |
int strncmp( const
char *s1, const char *s2, size_t n )
|
Compares up to n characters of
string s1
to s2. Returns a negative number if s1 < s2, zero if s1 == s2 or a positive number if s1 > s2. |
int strlen ( const
char *s)
|
Determines the length of string s.
The
number of characters preceding the terminating null character is returned. |
Let’s look at the string copy
function which is strcpy. The prototype of this function is
char *strcpy( char *s1, const char
*s2 )
Here the first argument is a pointer
to a character array or string s1 whereas the second argument is a pointer to a
string s2. The string s2 is copied to string s1 and a pointer to that resultant
string is returned. The string s2 remains the same. We can describe the string
s1 as the destination string and s2 as the source string. As the source remains
the same during the execution of strcpy and other string functions, the const
keyword is used before the name of source string. The const keyword prevents
any change in the source string (i.e. s2). If we want to copy a number of
characters of a string instead of the entire string, the function strncpy is
employed. The function strncpy has arguments a pointer to destination strings
(s1), a pointer to source string (s2) . The third argument is int n. Here n is
the number of characters which we want to copy from s2 into s1. Here s1 must be
large enough to copy the n number of characters.
The next function is strcat (string
concatenation). This function concatenates (joins) two strings. For example, in
a string, we have first name of a student, followed by another string, the last
name of the student is found. We can concatenate these two strings to get a
string, which holds the first and the last name of the student. For this
purpose, we use the strcat function. The prototype of this function is
char *strcat( char *s1, const char
*s2 )
This function writes the string s2
(source) at the end of the string s1(destination). The characters of s1 are not
overwritten. We can concatenate a number of characters of s2 to s1 by using the
function strncat. Here we provide the function three arguments, a character
pointer to s1, a character pointer to s2 while third argument is the number of
characters to be concatenated. The prototype of this function is written as
char *strncat( char *s1, const char
*s2, size_t n )
Example Code
/*Program to display the operation
of the strcpy() and strncpy()*/
# include<iostream.h>
# include<string.h>
void main()
{
char string1[15]="String1";
char string2[15]="String2";
cout<<"Before the copy :"<<endl;
cout<<"String 1:\t"<<string1<<endl;
cout<<"String 2:\t"<<string2<<endl;
//copy the whole string
strcpy(string2,string1); //copy string1 into string2
cout<<"After the copy :"<<endl;
cout<<"String 1:\t"<<string1<<endl;
cout<<"String 2:\t"<<string2<<endl;
//copy three characters of the string1 into string3
strncpy(string3, string1, 3);
cout << “strncpy (string3, string1, 3) = “ << string3 ;
}
# include<iostream.h>
# include<string.h>
void main()
{
char string1[15]="String1";
char string2[15]="String2";
cout<<"Before the copy :"<<endl;
cout<<"String 1:\t"<<string1<<endl;
cout<<"String 2:\t"<<string2<<endl;
//copy the whole string
strcpy(string2,string1); //copy string1 into string2
cout<<"After the copy :"<<endl;
cout<<"String 1:\t"<<string1<<endl;
cout<<"String 2:\t"<<string2<<endl;
//copy three characters of the string1 into string3
strncpy(string3, string1, 3);
cout << “strncpy (string3, string1, 3) = “ << string3 ;
}
Following is the output of the
program.
Before the copy :
String 1: String1
String 2: String2
After the copy :
String 1: String1
String 2: String1
Strncpy (string3, string1, 3) = Str
Before the copy :
String 1: String1
String 2: String2
After the copy :
String 1: String1
String 2: String1
Strncpy (string3, string1, 3) = Str
Lesson 30: String Search Functions
C provides another set of functions
relating to strings, called search functions. With the help of these functions,
we can do different types of search in a string. For example, we can find at
what position a specific character exists. We can search a character starting
from any position in the string. We can find the preceding or proceeding string
from a specific position. We can find a string inside another string. These
functions are given below.
Function prototype
|
Function description
|
char *strchr( const
char *s, int c );
|
Locates the first occurrence of
character c in string s. If c is found, a pointer to c in s is returned.
Otherwise, a NULL pointer is returned.
|
size_t strcspn(
const char *s1, const char *s2 );
|
Determines and returns the length
of the initial segment of string s1 consisting of characters not contained in
string s2.
|
size_t strspn( const
char *s1, const char *s2 );
|
Determines and returns the length
of the initial segment of string s1 consisting only of characters contained
in string s2.
|
char *strpbrk( const
char *s1, const char *s2 );
|
Locates the first occurrence in
string s1 of any character in string s2. If a character from string s2 is
found, a pointer to the character in string s1 is returned. Otherwise, a NULL
pointer is returned.
|
char *strrchr( const
char *s, int c );
|
Locates the last occurrence of c
in string s. If c is found, a pointer to c in string s is returned.
Otherwise, a NULL pointer is returned.
|
char *strstr( const
char *s1, const char *s2 );
|
Locates the first occurrence in
string s1 of string s2. If the string is found, a pointer to the string in s1
is returned. Otherwise, a NULL pointer is returned.
|
char *strtok( char
*s1, const char *s2 );
|
A sequence of calls to strtok breaks
string s1 into “tokens”—logical pieces such as words in a line of
text—separated by characters contained in string
s2. The first call contains s1 as the first argument, and subsequent calls to continue tokenizing the same string contain NULL as the first argument. A pointer to the current token is returned by each call. If there are no more tokens when the function is called, NULL is returned. |
Example Code
Here is an example, which shows the
use of different string search functions. The code of the program is given
below.
/*A program which shows string
search using <string.h> library*/
#include <iostream.h>
#include <string.h>
#include <stdlib.h>
main()
{
char s1[] = "Welcome to " ;
char s2[] = "the C Tutorial" ;
char s3[] = "Welcome to Karachi" ;
char city[] = "Karachi";
char province[] = "Sind";
char s[80];
char *pc;
int n;
cout << "s1 = " << s1 << endl << "s2 = " << s2 << endl ;
cout << "s3 = " << s3 << endl ;
// function for string length
cout << "The length of s1 = " << strlen(s1) << endl ;
cout << "The length of s2 = " << strlen(s2) << endl ;
cout << "The length of s3 = " << strlen(s3) << endl ;
strcpy(s, "Hyderabad"); // string copy
cout<<"The nearest city to "<< city << " is " <<s<< endl ;
strcat(s, " and "); // string concatenation
strcat(s,city);
strcat(s, " are in ");
strcat(s, province);
strcat(s, ".\n");
cout << s;
if (!(strcmp (s1,s2)))//!is used as zero is returned if s1 & s2 are equal
cout << "s1 and s2 are identical" << endl ;
else
cout << "s1 and s2 are not identical" << endl ;
if (!(strncmp (s1,s3,7))) // ! is used as zero is returned for equality
cout << "First 7 characters of s1 and s3 are identical" << endl ;
else
cout << "First 7 characters of s1 and s3 are not identical" << endl ;
}
#include <iostream.h>
#include <string.h>
#include <stdlib.h>
main()
{
char s1[] = "Welcome to " ;
char s2[] = "the C Tutorial" ;
char s3[] = "Welcome to Karachi" ;
char city[] = "Karachi";
char province[] = "Sind";
char s[80];
char *pc;
int n;
cout << "s1 = " << s1 << endl << "s2 = " << s2 << endl ;
cout << "s3 = " << s3 << endl ;
// function for string length
cout << "The length of s1 = " << strlen(s1) << endl ;
cout << "The length of s2 = " << strlen(s2) << endl ;
cout << "The length of s3 = " << strlen(s3) << endl ;
strcpy(s, "Hyderabad"); // string copy
cout<<"The nearest city to "<< city << " is " <<s<< endl ;
strcat(s, " and "); // string concatenation
strcat(s,city);
strcat(s, " are in ");
strcat(s, province);
strcat(s, ".\n");
cout << s;
if (!(strcmp (s1,s2)))//!is used as zero is returned if s1 & s2 are equal
cout << "s1 and s2 are identical" << endl ;
else
cout << "s1 and s2 are not identical" << endl ;
if (!(strncmp (s1,s3,7))) // ! is used as zero is returned for equality
cout << "First 7 characters of s1 and s3 are identical" << endl ;
else
cout << "First 7 characters of s1 and s3 are not identical" << endl ;
}
Following is the output of the
program.
S1 = Welcome to
S2 = the C Tutorial
S3 = Welcome to Karachi
The length of s1 = 11
The length of s2 = 18
The length of s3 = 18
The nearest city to Karachi is Hyderabad
Hyderabad and Karachi are in Sind.
S1 and s2 are not identical
First 7 characters of s1 and s3 are identical
S1 = Welcome to
S2 = the C Tutorial
S3 = Welcome to Karachi
The length of s1 = 11
The length of s2 = 18
The length of s3 = 18
The nearest city to Karachi is Hyderabad
Hyderabad and Karachi are in Sind.
S1 and s2 are not identical
First 7 characters of s1 and s3 are identical
Lesson 31: File
Handling
We will discuss files and file
handling in this lesson. The topic is going to be a sequel of the subjects like
bit, bytes, character, numbers etc.
In the previous lessons, we have
talked about strings, which are actually character arrays. While typing a
letter or a document in word processor, we actually deal with big collection of
words like sentences, not with bits and bytes. These combinations of
characters, words, sentences and paragraph are called as files.
The files in the computer are
classified under different categories. Primarily, there are two types of files
i.e.
- Data files
- Executable program files
Data files include our simple text
files, or word processor file etc. On the other hand, the executable program
files run the program.
Text file Handling
Let's see what are the basic steps
needed for file handling. Suppose we have a file on the disk and want to open
it. Then read from or write into the file before finally closing it. The basic
steps of file handling are:
- Open the file
- Read and write
- Close the file
We have been using cin and cout a
lot in the programs. We know that these are the doors by which data can enter
and come out. cin is used to enter the data and cout is used to display the
data on the screen.
Technically, these are known as
streams in C++. This is how 'C++ language' handles files. For this purpose, the
header file to be used is <fstream.h> (i.e. file stream). Whenever using
files in the program, we will include this header file as
#include <fstream.h>
These streams are used the way we
have been employing cin and cout but we can do more with these streams.
While handling files, one can have
three options. Firstly, we will only read the file. It means the file is used
as input for the program. We need to have a stream for input file i.e. ifstream
(input file stream).
Similarly, if we want to write in
some file, ofstream (output file stream) can be used. Sometimes we may need to
read and write in the same file. One way is to read from a file, manipulate it
and write it in another file, delete the original file and renaming the new
file with the deleted file name. We can read, write and manipulate the same
file using fstream.h.
Let's us see how can we use these
files in our programs. First, we have to include the fstream.h in our programs.
Then we need to declare file streams. cin and cout are predefined streams which
needed not to be declared. We can declare file stream as:
ifstream inFile; // object for
reading from a file
ofstream outFile; // object for writing to a file
ofstream outFile; // object for writing to a file
The variables inFile and outFile are
used as 'handle to refer' files. These are like internal variables, used to
handle the files that are on the disk. We will use inFile as declared above to
read a file. Any meaningful and self-explanatory name can be used. To deal with
a payroll system, payrollDataFile can be used as a file stream variable i.e.
ifstream payrollDataFile;.
The topic of file handling will
continue in the following lessons.
Lesson 32: Input File Handling
|
Consider the following statement:
ifstream myFile;
Here myFile is an internal variable
used to handle the file. So far, we did not attach a file with this handle.
Before going for attachment, we will have to open a file. Logically, there is
function named ‘open’ to open a file. While associating a file with the
variable myFile, the syntax will be as under:
myFile.open(filename);
You have noted that this is a new
way of function calling. We are using dot (.) between the myFile and open
function. myFile is an object of ifstream while open() is a function of
ifstream. The argument for the open function filename is the name of the file
on the disk. The data type of argument filename is character string, used to
give the file name in double quotation marks. The file name can be simple file
name like “payroll.txt”. It can be fully qualified path name like “C:\myprogs\payroll.txt”.
In the modern operating systems like
Windows, disks are denoted as C: or D: etc. We have different folders in it
like ‘myprogs’ and can have files in this folder. The fully qualified path
means that we have to give the path beginning from C:\. To understand it
further, suppose that we are working in the folder ‘myprogs’ and our source and
executable files are also in this folder. Here, we don’t need to give a
complete path and can write it as “payroll.txt”. If the file to be opened is in
the current directory (i.e. the program and text file are in the same folder),
you can open it by simply giving the name. If you are not familiar with the
windows file system, get some information from windows help system. It is a
hierarchical system. The disk, which is at the top, contains folder and files.
Folders can contain subfolders and files. It is a multi-level hierarchical
system. In UNIX, the top level is “root”, which contains files and directories.
So it’s like a bottom-up tree. Root is at the top while the branches are
spreading downward. Here ‘root’ is considered as root of a tree and files or
subfolders are branches. To open a file, we use open function while giving it
the name of the file as fully qualified path name or simple name. Then we also
tell it what we want to do with that file i.e. we want to read that file or
write into that file or want to modify that file. We have declared myFile as
ifstream (input file stream) variable so whenever we tried to open a file with
ifstream variable it can only be opened for input. Once the file is open, we
can read it. The access mechanism is same, as we have been using with streams.
So to read a word from the file we can write as:
myFile >> c;
So the first word of the file will
be read in c, where c is a character array. It is similar as we used with cin.
There are certain limitations to this. It can read just one word at one time.
It means, on encountering a space, it will stop reading further. Therefore, we
have to use it repeatedly to read the complete file. We can also read multiple
words at a time as:
myFile >> c1 >> c2
>> c3;
The first word will be read in c1,
2nd in c2 and 3rd in c3. Before reading the file, we should know some
information regarding the structure of the file. If we have a file of an
employee, we should know that the first word is employee’s name, 2nd word is
salary etc, so that we can read the first word in a string and 2nd word in an
int variable. Once we have read the file, it must be closed. It is the
responsibility of the programmer to close the file. We can close the file as:
myFile.close();
The function close() does not
require any argument, as we are going to close the file associated with myFile.
Once we close the file, no file is associated with myfile now. Let’s have a
look on error checking mechanism while handling files. Error checking is very
important. Suppose we have to open a text file myfile.txt from the current
directory, we will write as:
ifstream myFile;
myFile.open(“myfile.txt”);
myFile.open(“myfile.txt”);
If this file does not exist on the
disk, the variable myFile will not be associated with any file. There may be
many reasons due to which the myFile will not be able to get the handle of the
file. Therefore, before going ahead, we have to make sure that the file opening
process is successful. We can write as:
if (!myFile)
{
cout << “There is some error opening file” << endl;
cout << “ File cannot be opened” << end;
exit(1);
}
else
cout << “ File opened successfully “ << end;
{
cout << “There is some error opening file” << endl;
cout << “ File cannot be opened” << end;
exit(1);
}
else
cout << “ File opened successfully “ << end;
Example Code
Let’s write a simple program, which
will read from a file ‘myfile.txt’ and print it on the screen. “myfile.txt”
contains employee’s name, salary and department of employees. Following is the
complete program along with “myfile.txt” file.
Sample “myfile.txt”.
Name Salary Department
Aamir 12000 Sales
Amara 15000 HR
Adnan 13000 IT
Afzal 11500 Marketing
Name Salary Department
Aamir 12000 Sales
Amara 15000 HR
Adnan 13000 IT
Afzal 11500 Marketing
Code of the program
/*
* This program reads from a txt file “myfile.txt” which contains the
* employee information
*/
#include <iostream.h>
#include <fstream.h>
main()
{
char name[50]; // used to read name of employee from file
char sal[10]; // used to read salary of employee from file
char dept[30]; // used to read dept of employee from file
ifstream inFile; // Handle for the input file
char inputFileName[] = "myfile.txt"; // file name, this file is in the
//current directory
inFile.open(inputFileName); // Opening the file
// checking that file is successfully opened or not
* This program reads from a txt file “myfile.txt” which contains the
* employee information
*/
#include <iostream.h>
#include <fstream.h>
main()
{
char name[50]; // used to read name of employee from file
char sal[10]; // used to read salary of employee from file
char dept[30]; // used to read dept of employee from file
ifstream inFile; // Handle for the input file
char inputFileName[] = "myfile.txt"; // file name, this file is in the
//current directory
inFile.open(inputFileName); // Opening the file
// checking that file is successfully opened or not
if (!inFile)
{
cout << "Can't open input file named " << inputFileName << endl;
exit(1);
}
// Reading the complete file word by word and printing on screen
while (!inFile.eof())
{
inFile >> name >> sal >> dept;
cout << name << "\t" << sal << " \t" << dept << endl;
}
inFile.close();
}
{
cout << "Can't open input file named " << inputFileName << endl;
exit(1);
}
// Reading the complete file word by word and printing on screen
while (!inFile.eof())
{
inFile >> name >> sal >> dept;
cout << name << "\t" << sal << " \t" << dept << endl;
}
inFile.close();
}
Output of the program.
Name
Salary Department
Aamir 12000 Sales
Amara 15000 HR
Adnan 13000 IT
Afzal 11500 Marketing
Aamir 12000 Sales
Amara 15000 HR
Adnan 13000 IT
Afzal 11500 Marketing
In the above program, we have
declared three variables for reading the data from the input file (i.e. name,
sal, dept). The text file “myfile.txt” and the program file should be in the
same directory as there is no fully qualified path used with the file name in
the open() function. After opening the file, we will check that file is
successfully opened or not. If there is some error while opening the file, we
will display the error on screen and exit from the program. The statement
exit(1) is used to exit from the program at any time and the control is given
back to the operating system. Later, we will read all the data from the file
and put it into the variables. The condition in ‘while loop’ is “!inFile.eof()”
means until the end of file reached. The function eof() returns true when we
reached at the end of file.
Lesson 33: Output File Handling
Let’s talk about the output file
handling. You can do several things with output files like, creation of a new
file on the disk and writing data in it. Secondly, we may like to open an
existing file and overwrite it in such a manner that all the old information is
lost from it and new information is stored. Thirdly, we may want to open an
existing file and append it in the end. Fourthly, an existing file can be
opened and modified in a way that it can be written anywhere in the file.
Therefore, when we open a file for output we have several options and we might
use any one of these methods. All these things are related to the file-opening
mode. The actual syntax of open function is:
open (filename, mode)
The first argument is the name of
the file while the second will be the mode in which file is to be opened. Mode
is basically an integer variable but its values are pre-defined. When we open a
file for input, its mode is input file that is defined and available through
the header files, we have included. So the correct syntax of file opening for
input is:
myFile.open(“myfile.txt” , ios::in);
The 2nd argument ios::in associates
myFile stream object with the “myfile.txt” for input. Similarly, for output
files, there are different modes available. To open a file for output mode,
ios::out is used. Here is the complete list of modes:
Mode
|
Meaning
|
in
|
Open a file or stream for
extraction (input)
|
out
|
Open a file or stream for
insertion (output)
|
app
|
Append rather than truncate an
existing file. Each insertion(output) will be written to the end of the file
|
trunc
|
Discards the file’s contents if it
exists. (similar to default behavior)
|
ate
|
Opens the file without truncating,
but allows data to be written anywhere in the file
|
binary
|
Treat the file as binary rather
than text. A binary file has data stored in internal formats, rather than
readable text format
|
If a file is opened with ios::out
mode, a new file is created. However, if the file already exists, its contents
will be deleted and get empty unless you write something into it. If we want to
append into the file, the mode will be ios::app. When we write into the file,
it will be added in the end of the file. If we want to write anywhere in the
file, the mode is ios::ate. We can position at some particular point and can
write there. It is like append mode. But in ‘ate mode’ we can write anywhere in
the file. With the trunc mode, the file is truncated, it is similar to out
mode.
Example Code
/*
* This program writes into a txt file “myfileOut.txt” which contains the
* “Welcome to the C Tutorial”
*/
#include <iostream.h>
#include <fstream.h>
main()
{
ofstream outFile; // Handle for the input file
char outputFileName[] = "myFileOut.txt"; // The file is created in the
//current directory
char ouputText[100] = "Welcome to the C Tutorial"; // used to write into
//the file
outFile.open(outputFileName, ios::out); // Opening the file
// checking that file is successfully opened or not
if (!outFile)
{
cout << "Can't open input file named " << outputFileName << endl;
exit(1);
}
// Writing into the file
outFile << ouputText;
outFile.close();
}
* This program writes into a txt file “myfileOut.txt” which contains the
* “Welcome to the C Tutorial”
*/
#include <iostream.h>
#include <fstream.h>
main()
{
ofstream outFile; // Handle for the input file
char outputFileName[] = "myFileOut.txt"; // The file is created in the
//current directory
char ouputText[100] = "Welcome to the C Tutorial"; // used to write into
//the file
outFile.open(outputFileName, ios::out); // Opening the file
// checking that file is successfully opened or not
if (!outFile)
{
cout << "Can't open input file named " << outputFileName << endl;
exit(1);
}
// Writing into the file
outFile << ouputText;
outFile.close();
}
The file “myFileOut.txt”:
Welcome to the C Tutorial
Welcome to the C Tutorial
Lesson 34: Advanced File Handling
We can also read a line from the
file. The benefit of reading a line is efficiency. But clarity should not be
sacrificed over efficiency. We read from the disk and write to the disk. The
disk is an electro mechanical device. It is the slowest component in the
computer. Other parts like processors, memory etc are very fast nowadays i.e.
in Ghz. When we talk about hard disk, we say its average access time is 7 mili
sec. It means when we request hard disk to get data it will take 7 mili sec
(7/1000 of a sec) to get the data where as processor is running on GHz speed, a
thousand million cycles per sec. Processor and memory are much much faster than
the hard disk. Therefore reading a single character from the file is too slow.
Nowadays, the buffering and other techniques are used to make the disk access
faster. It will be quite efficient if we read the data in bigger chunks i.e.
64k or 256k bytes and also write in bigger chunks. Today’s operating system
applies the buffering and similar techniques. Instead of reading and writing
character-bycharacter or word-by-word, reading and writing line by line is
efficient. A function is available for this purpose i.e. getLine() for input
file stream and putLine() for output file stream. The syntax of getLine() is as
follows:
char name[100];
int maxChar = 100;
int stopChar = ‘o’;
inFile.getLine(name, maxChar, stopChar);
int maxChar = 100;
int stopChar = ‘o’;
inFile.getLine(name, maxChar, stopChar);
The first argument is a character
array. The array should be large enough to hold the complete line. The second
argument is the maximum number of characters to be read. The third one is the
character if we want to stop somewhere. Suppose we have an input file
containing the line ‘Hello World’, then the statements:
char str[20];
inFile.getLine(str, 20, ‘W’);
cout<<“The line read from the input file till W is ”<< str;
inFile.getLine(str, 20, ‘W’);
cout<<“The line read from the input file till W is ”<< str;
The getLine() function will read
‘Hello ’. Normally we do not use the third argument. The default value for the
third argument is new line character so getLine() will read the complete line
up to the new line character. The new line character will not be read. The line
read will be stored in the array, used in the first argument. It is our
responsibility that the array should be large enough to hold the entire line.
We can manipulate this data. Using the getLine() repeatedly to read the file is
much more efficient rather than using the get() function. As the getLine()
function does not read the new line character, we have to put it explicitly. If
we have large file to be read, the difference in speed with both the programs
i.e. using get() and getLine() can be noted.
Example Code:
Write a program which reads a file
using the getLine() function and display it on the screen.
Sample input file:
This is a test program
In this program we learn how to use getLine() function
This function is faster than using the get() function
This is a test program
In this program we learn how to use getLine() function
This function is faster than using the get() function
The complete code of
the program:
/*
* This program reads from a txt file line by line
*
*/
#include <iostream.h>
#include <fstream.h>
main()
{
ifstream inFile; // Handle for the input file
* This program reads from a txt file line by line
*
*/
#include <iostream.h>
#include <fstream.h>
main()
{
ifstream inFile; // Handle for the input file
char inputFileName[] =
"test.txt";
// file name, this file is in the current directory
const int MAX_CHAR_TO_READ = 100;
// maximum character to read in one line
char completeLineText[MAX_CHAR_TO_READ]; // to be used in getLine function
inFile.open(inputFileName); // Opening the file
// checking that file is successfuly opened or not
if (!inFile)
{
cout<<"Can't open input file named "<<inputFileName<< endl;
exit(1);
}
// Reading the complete file line by line and printing on screen
while (!inFile.eof())
{
inFile.getline(completeLineText, MAX_CHAR_TO_READ);
cout << completeLineText << endl;
}
inFile.close();
}
// file name, this file is in the current directory
const int MAX_CHAR_TO_READ = 100;
// maximum character to read in one line
char completeLineText[MAX_CHAR_TO_READ]; // to be used in getLine function
inFile.open(inputFileName); // Opening the file
// checking that file is successfuly opened or not
if (!inFile)
{
cout<<"Can't open input file named "<<inputFileName<< endl;
exit(1);
}
// Reading the complete file line by line and printing on screen
while (!inFile.eof())
{
inFile.getline(completeLineText, MAX_CHAR_TO_READ);
cout << completeLineText << endl;
}
inFile.close();
}
The output of the program is:
This is a test program
In this program we learn how to use getLine() function
This function is faster than using the get() function
This is a test program
In this program we learn how to use getLine() function
This function is faster than using the get() function
Lesson 35: Random Access Files
|
Here we will discuss how to access
files randomly, forward and backward. Before moving forward or backward within
a file, one important factor is the current position inside the file.
Therefore, we must understand that there is a concept of file position (or
position inside a file) i.e. a pointer into the file. While reading from and
writing into a file, we should be very clear from where (which location inside
the file) our process of reading or writing will start. To determine this file
pointer position inside a file, we have two functions tellg() and tellp().
Position in a File
Let’s say we have opened a file
stream myfile for reading (getting), myfile.tellg () gives us the current get
position of the file pointer. It returns a whole number of type long, which is
the position of the next character to be read from that file. Similarly, tellp
() function is used to determine the next position to write a character while
writing into a file. It also returns a long number.
For example, given an fstream object
aFile:
Streampos original = aFile.tellp();
//save current position
aFile.seekp(0, ios::end); //reposition to end of file
aFile << x; //write a value to file
aFile.seekp(original); //return to original position
aFile.seekp(0, ios::end); //reposition to end of file
aFile << x; //write a value to file
aFile.seekp(original); //return to original position
So tellg () and tellp () are the two
very useful functions while reading from or writing into the files at some
certain positions.
Setting the Position
The next thing to learn is how can
we position into a file or in other words how can we move forward and backward
within a file. Suppose we want to open a file and start reading from 100th
character. For this, we use seekg () and seekp () functions. Here seekg ()
takes us to a certain position to start reading from while seekp () leads to a
position to write into. These functions seekg () and seekp () requires an
argument of type long to let them how many bytes to move forward or backward.
Whether we want to move from the beginning of a file, current position or the
end of the file, this move forward or backward operation, is always relative to
some position.. From the end of the file, we can only move in the backward
direction. By using positive value, we tell these functions to move in the
forward direction .Likewise, we intend to move in the backward direction by
providing a negative number. By writing:
aFile. seekg (10L, ios::beg)
We are asking to move 10 bytes
forward from the begining of the file. Similarly, by writing:
aFile. seekg (20L, ios::cur)
We are moving 20 bytes in the
forward direction starting from the current position. Remember, the current
position can be obtained using the tellg () function.By writing:
aFile. seekg (-10L, ios:cur)
The file pointer will move 10 bytes
in the backward direction from the current position. With seekg (-100L,
ios::end), we are moving in the backward direction by 100 bytes starting from
the end of the file. We can only move in the forward direction from the
beginning of the file and backward from the end of the file.
seekg() and tellg() Functions
One of the useful things we can do
by employing these functions is to determine the length of the file. Think
about it, how can we do it. In the previous lessons, we have discussed strlen
() function that gives the number of characters inside a string. This function
can also be used to determine the length of the string placed inside an array.
That will give us the number of characters inside the string instead of the
array length. As you already know that the length of the array can be longer
than the length of the string inside it. For example, if we declare an array of
100 characters but store "Welcome to the C Tutorial" string in it,
the length of the string is definitely smaller than the actual size of the
array and some of the space of the array is unused. Similarly in case of files,
the space occupied by a file (file size) can be more than the actual data
length of the file itself. Why the size of the file can be greater than the
actual data contained in that file? The answer is little bit off the topic yet
it is be good to discuss. As you know, the disks are electromagnetic devices.
They are very slow as compared to the controlling electronic devices like
Processors and RAM (Random Access Memory). If we want to perform read or write
operations to the disk in character by character fashion, it will be very wasteful
of computer time. Take another example. Suppose ,we want to write a file, say
53 bytes long to the disk . After writing it, the next file will start from
54th byte on the disk.
Obviously, this is very wasteful
operation of computer time. Moreover, it is also very complex in terms of
handling file storage on the disk. To overcome this problem, disks are divided
into logical blocks (chunks or clusters) and size of one block is the minimum
size to read and write to the disk. While saving a file of 53 bytes, we can’t
allocate exactly 53 bytes but have to utilize at least one block of disk space.
The remaining space of the block except first 53 bytes, goes waste. Therefore,
normally the size of the file (which is in blocks) is greater than the actual
data length of the file. When this file will be read from the disk, the whole
chunk (block) is read instead of the actual data length. By using seekg ()
function, we can know the actual data length of the file. For that purpose, we
will open the file and go to the end of the file by asking the seekg ()
function to move 0 bytes from the end of the file as: seekg (0, ios::end).
Afterwards, (as we are on end of file position), we will call tellg () to give
the current position in long number. This number is the actual data bytes
inside the file. We used seekg () and tellg () functions combination to
determine the actual data length of a file.
/* This is a sample program to
determine the length of a file. The program accepts the name of the file as a
command-line argument. */
#include <fstream.h>
#include <stdlib.h>
ifstream inFile;
ofstream outFile;
main(int argc, char **argv)
{
inFile.open(argv[1]);
if(!inFile)
{
cout << "Error opening file in input mode"<< endl;
}
/* Determine file length opening it for input */
inFile.seekg(0, ios::end); //Go to the end of the file
long inSize = inFile.tellg(); //Get the file pointer position
cout << "The length of the file (inFile) is: " << inSize;
inFile.close();
/* Determine file length opening it for output */
#include <fstream.h>
#include <stdlib.h>
ifstream inFile;
ofstream outFile;
main(int argc, char **argv)
{
inFile.open(argv[1]);
if(!inFile)
{
cout << "Error opening file in input mode"<< endl;
}
/* Determine file length opening it for input */
inFile.seekg(0, ios::end); //Go to the end of the file
long inSize = inFile.tellg(); //Get the file pointer position
cout << "The length of the file (inFile) is: " << inSize;
inFile.close();
/* Determine file length opening it for output */
outFile.open(argv[1], ios::app);
if(!outFile)
{
cout << "Error opening file in append mode"<< endl;
}
outFile.seekp(0, ios::end);
long outSize = outFile.tellp();
cout << "\nThe length of the file (outFile) is: " << outSize;
outFile.close();
}
if(!outFile)
{
cout << "Error opening file in append mode"<< endl;
}
outFile.seekp(0, ios::end);
long outSize = outFile.tellp();
cout << "\nThe length of the file (outFile) is: " << outSize;
outFile.close();
}
Run this program to see its output
that shows different results for both input and output modes.
Lesson 36: Efficient File Handling
Let’s consider an example. We know
how to read a file character by character, write into another file or on the
screen. If we want to write into a file after reading another file, there are
already enough tools to get (read) one character from a file and put (write)
into the other one. We can use inputFile.getc () to get a character and
outputFile.putc () to write a character into a file. As mentioned earlier,
there is very inefficient way of doing things . We also know that for reading
and writing to disk, processing in chunks is more efficient. Can we handle more
data than a single byte or a single line? The answer is yes. We can use read ()
and write () functions for this purpose. These functions are binary functions
and provided as a part of the stream functions. The term binary means that they
read and write in binary mode, not in characters. We tell a location in memory
to read () function to write the read data and with the number of bytes to read
or write. Usually, read(arrayname, number of bytes) e.g. read(a, 10). Now
depending on our computer’s memory, we can have a very large data in it. It may
be 64K.
Sample Code
/* This is a sample program to
demonstrate the use of open(), close(), seekg(), get() functions and streams.
It expects a file named my-File.txt in the current directory having some data
strings inside it. */
#include <fstream.h>
#include <stdlib.h>
/* Declare the stream objects */
ifstream inFile;
ofstream scrn, prnt;
main()
{
char inChar;
inFile.open("my-File.txt", ios::in); // Open the file for input
if(!inFile)
{
cout << "Error opening file"<< endl;
}
scrn.open("CON", ios::out); // Attach the console with the output stream
while(inFile.get(inChar)) // Read the whole file one character at a time
{
scrn << inChar; // Insert read character to the output stream
}
scrn.close(); // Close the output stream
inFile.seekg(0l, ios::beg); // Go to the beginning of the file
prnt.open("LPT1", ios::out);// Attach the output stream with the LPT1 port
while(inFile.get(inChar)) // Read the whole file one character at a time
{
prnt << inChar; // Insert read character to the output stream
}
prnt.close(); // Close the output stream
inFile.close(); // Close the input stream
}
#include <fstream.h>
#include <stdlib.h>
/* Declare the stream objects */
ifstream inFile;
ofstream scrn, prnt;
main()
{
char inChar;
inFile.open("my-File.txt", ios::in); // Open the file for input
if(!inFile)
{
cout << "Error opening file"<< endl;
}
scrn.open("CON", ios::out); // Attach the console with the output stream
while(inFile.get(inChar)) // Read the whole file one character at a time
{
scrn << inChar; // Insert read character to the output stream
}
scrn.close(); // Close the output stream
inFile.seekg(0l, ios::beg); // Go to the beginning of the file
prnt.open("LPT1", ios::out);// Attach the output stream with the LPT1 port
while(inFile.get(inChar)) // Read the whole file one character at a time
{
prnt << inChar; // Insert read character to the output stream
}
prnt.close(); // Close the output stream
inFile.close(); // Close the input stream
}
Sample Code 2
/* This sample code
demostrates the use of fstream and seekg() function. It will create a file
named my-File.txt write alphabets into it, destroys the previous contents */
#include <fstream.h>
fstream rFile; // Declare the stream object
main()
{
char rChar;
/* Opened the file in both input and output modes */
rFile.open("my-File.txt", ios::in || ios::out);
if(!rFile)
{
cout << "error opening file"<< endl;
}
/* Run the loop for whole alphabets */
for ( rChar ='A'; rChar <='Z'; rChar++)
{
rFile << rChar; // Insert the character in the file
}
rFile.seekg(8l, ios::beg); // Seek the beginning and move 8 bytes forward
rFile >>rChar; // Take out the character from the file
cout << "the 8th character is " << rChar ;
rFile.seekg(-16l, ios::end);// Seek the end and move 16 positions backword
rFile >>rChar; // Take out the character at the current position
cout << "the 16th character from the end is " << rChar ;
rFile.close(); // Close the file
}
#include <fstream.h>
fstream rFile; // Declare the stream object
main()
{
char rChar;
/* Opened the file in both input and output modes */
rFile.open("my-File.txt", ios::in || ios::out);
if(!rFile)
{
cout << "error opening file"<< endl;
}
/* Run the loop for whole alphabets */
for ( rChar ='A'; rChar <='Z'; rChar++)
{
rFile << rChar; // Insert the character in the file
}
rFile.seekg(8l, ios::beg); // Seek the beginning and move 8 bytes forward
rFile >>rChar; // Take out the character from the file
cout << "the 8th character is " << rChar ;
rFile.seekg(-16l, ios::end);// Seek the end and move 16 positions backword
rFile >>rChar; // Take out the character at the current position
cout << "the 16th character from the end is " << rChar ;
rFile.close(); // Close the file
}
Lesson 37: Structures
|
In this lesson, we will discuss the
concept of structures which is a very interesting part of C language. We can
understand ‘structure’ with the example of students of a class. Suppose we have
data about students of a class i.e. name, addresses, date of birth, GPA and
courses of study. This information is related to only a single entity i.e.
student. To understand the matter further, we can think of a car with its
specifications like model, manufacturer company, number of seats and so on. But
there is always a requirement in most of our data processing applications that
the relevant data should be grouped and handled as a group. This is what the
concept of structure is. In structure, we introduce a new data type. In the
previous lessons, we have been dealing with int, float, double and char in our
programs. You are fully familiar with the term ’strings’ but there is no data
type called strings. We have used ‘array of char’ as strings. While dealing
with numbers, there is no built-in mechanism to handle the complex numbers.
This means that there is no data type like complex. The FORTRAN language
(Formula Translation) written for scientific application, has a complex data
type. Therefore, in FORTRAN, we can say complex x; now x is a variable of type
complex and has a real part and an imaginary part. There is no complex data
type in C and C++.
In C, C++ we deal with such
situations with structures. So a structure is not simply a grouping of real
world data like students, car etc, it also has mathematical usage like complex
number. The definition of structure is as under: “A structure is a
collection of variables under a single name. These variables can be of
different types, and each has a name that is used to select it from the
structure”.
Declaration of a Structure:
Structures are syntactically defined
with the word struct. So struct is another keyword that cannot be used as
variable name. Followed by the name of the structure. The data, contained in
the structure, is defined in the curly braces. All the variables that we have
been using can be part of structure. For example:
struct student{
char name[60];
char address[100];
float GPA;
};
char name[60];
char address[100];
float GPA;
};
Here we have a declared a structure,
‘student’ containing different elements. The name of the student is declared as
char array. For the address, we have declared an array of hundred characters.
To store the GPA, we defined it as float variable type. The variables which are
part of structure are called data members i.e. name, address and GPA are data
members of student. Now this is a new data type which can be written as:
student std1, std2;
Here std1 and std2 are variables of
type student like int x, y; x and y in this case are variables of int data
type. This shows the power of C and C++ language and their extensibility. Moreover,
it means that we can create new data types depending upon the requirements.
Structures may also be defined at the time of declaration in the following
manner:
struct student{
char name[60];
char address[100];
float GPA;
}std1, std2;
char name[60];
char address[100];
float GPA;
}std1, std2;
We can give the variable names after
the closing curly brace of structure declaration. These variables are in a
comma-separated list. Structures can also contain pointers which also fall
under the category of data type. So we can have a pointer to something as a
part of a structure. We can’t have the same structure within itself but can
have other structures. Let’s say we have a structure of an address.as:
struct address{
char streetAddress[100];
char city[50];
char country[50];
}
char streetAddress[100];
char city[50];
char country[50];
}
Now the structure address can be a
part of student structure. We can rewrite student structure as under:
struct student{
char name[60];
address stdAdd;
float GPA;
};
char name[60];
address stdAdd;
float GPA;
};
Here stdAdd is a variable of type
Address and a part of student structure. So we can have pointers and other
structures in a structure. We can also have pointers to a structure in a
structure. We know that pointer hold the memory address of the variable. If we
have a pointer to an array, it will contain the memory address of the first
element of the array. Similarly, the pointer to the structure points to the
starting point where the data of the structure is stored.
The pointers to structure can be
defined in the following manner i.e.
student *sptr;
Here sptr is a pointer to a data
type of structure student. Briefly speaking, we have defined a new data type.
Using structures we can declare:
• Simple variables of new structure
• Pointers to structure
• Arrays of structure
• Pointers to structure
• Arrays of structure
There are also limitation with
structures as we can not say std1 + std2; As the operator plus (+) does not
know how to add two structures. We will learn to overcome these limitations at
the advanced stage. On the other hand, assignment of structures works.
Therefore if s1 and s2 are of type student structure, we can say that s1 = s2.
The assignment works because the structure is identical. So the name will be
copied to the name, address to address and so on.
Lesson 38: Working with Structures
|
We have so far learnt how to define
a structure and declare its variables. Let’s see how can we put the values in
its data members. The following example can help us understand the phenomenon
further.
struct student{
char name[64];
char course[128];
int age;
int year;
};
student s1, s2, s3;
char name[64];
char course[128];
int age;
int year;
};
student s1, s2, s3;
Once the structure is defined, the
variables of that structure type can be declared. Initialization may take place
at the time of declaration i.e.
student s1 = {“Ali”, “C++
Programming”, 19, 2002 };
In the above statement, we have
declared a variable s1 of data type student structure and initialize its data
member. The values of data members of s1 are comma separated in curly braces.
“Ali” will be assigned to name, “C++ Programming” will be assigned to the
course, 19 to age and 2002 to year. So far we have not touched these data
members directly. To access the data members of structure, dot operator (.) is
used. Therefore while manipulating name of s1, we will say s1.name. This is a
way of referring to a data member of a structure. This may be written as:
s1.age = 20;
The above statement will assign the value 20 to the age data member of structure s1. To display the name of s1 we can write it as:
The above statement will assign the value 20 to the age data member of structure s1. To display the name of s1 we can write it as:
cout << “The name of s1 = “
<< s1.name;
Other data members can be displayed
on the screen in the same fashion.
Here is a simple example showing the
initialization and displaying the structure.
/* Simple program showing the
initialization of structure.*/
#include <iostream.h>
main()
{
// Declaring student structure
struct student{
char name[64];
char course[64];
int age;
int year;
};
// Initializing the structure
student s1 = {"Ali", "C++ Programming", 22, 2002};
cout << "Displaying the structure data members" << endl;
cout << "The name is " << s1.name << endl;
cout << "The course is " << s1.course << endl;
cout << "The age is " << s1.age << endl;
cout << "The year is " << s1.year << endl;
}
#include <iostream.h>
main()
{
// Declaring student structure
struct student{
char name[64];
char course[64];
int age;
int year;
};
// Initializing the structure
student s1 = {"Ali", "C++ Programming", 22, 2002};
cout << "Displaying the structure data members" << endl;
cout << "The name is " << s1.name << endl;
cout << "The course is " << s1.course << endl;
cout << "The age is " << s1.age << endl;
cout << "The year is " << s1.year << endl;
}
The output of the above program is:
Displaying
the structure data members
The name is Ali
The course is C++ Programming
The age is 22
The year is 2002
The name is Ali
The course is C++ Programming
The age is 22
The year is 2002
Here, s1 is a unit. The data members
have been grouped together. If we have s1 and s2 as two variables of student
type and want to copy the data of s1 to s2, it can be written as:
s2 = s1;
Lesson 39: Arrays, Pointers, Functions, Structures
Functions and structures
We can pass structures to functions. Structures are passed into functions as per the C/C++ calling conventions by value. In other words, a copy of entire structure is put on the stack. The function is called which removes it from the stack and uses the structure. We can also pass the structures by reference to function. This can be performed in the same way we do with the normal variables i.e. pass the address of the structure to the function. This is call by reference. When we pass an array to a function, the reference of the array is passed to the function. Any change in the array elements changes the original array. Suppose we have a structure containing an array. What will happen to the array if the structures are passed as value? Is the array passed as value or reference? As the array is a part of structure, it will be passed as value. The advantage of ‘pass by value’ process is that if the function makes some changes to the array elements, it does not affect the original array. However, it may be disadvantageous as the complete array is copied on the stack and we can run out of memory space. So be careful while passing the structures to functions. We know that functions return value, int, char etc. Similarly functions can also return structures. In a way, the behavior of structure is same as ordinary data type.Structures and Pointers
Suppose we have a pointer to structure as student *sptr; here sptr is a pointer to student. Now s1 is a variable of type student and sptr = &s1 and sptr is pointing to s1. How can we access the data with sptr? We cannot say *sptr.name. The precedence of dot operator (.) is higher than * operator. So dot operator is evaluated first and then * operator. The compiler will give error on the above statement. To get the results, we have to evaluate * operator first i.e. (*sptr).name will give the desired result. There is another easy and short way to access the structure’s data member i.e. using the arrow (->) in place of dot operator. We normally use the arrow (-> i.e. minus sign and then the greater than sign) to manipulate the structure’s data with pointers. So to access the name with sptr we will write:sptr->name;
Remember the difference between the access mechanism of structure while using the simple variable and pointer. While accessing through a simple variable, use dot operator i.e. s1.name While accessing through the pointer to structure, use arrow operator i.e. sptr- >name;
Following is the example, depicting the access mechanism of structure’s data member using the pointer to structure.
/* This program shows the access of structure data members with pointer to structure */
#include <iostream.h>
main()
{
// Declaration of student structure
struct student{
char name[64];
char course[64];
int age;
int year;
};
// Initializing the s1
student s1 = {"Ali", "C++ Programming", 22, 2002};
student *sptr;
// Assigning a structure to pointer
sptr = &s1;
cout << "Displaying the structure data members using pointers" << endl;
cout << "Using the * operator" << endl;
cout << endl;
cout << "The name is " << (*sptr).name << endl;
cout << "The course is " << (*sptr).course << endl;
cout << "The age is " << (*sptr).age << endl;
cout << "The year is " << (*sptr).year << endl;
cout << endl;
cout << "Using the -> operator" << endl;
cout << endl;
cout << "The name is " << sptr->name << endl;
cout << "The course is " << sptr->course << endl;
cout << "The age is " << sptr->age << endl;
cout << "The year is " << sptr->year << endl;
}
The output of the program is:
Displaying the structure data members using pointers
Using the * operator
The name is Ali
The course is C++ Programming
The age is 22
The year is 2002
Using the -> operator
The name is Ali
The course is C++ Programming
The age is 22
The year is 2002
Arrays of structures
Let’s discuss the arrays of structure. The declaration is similar as used to deal with the simple variables. The declaration of array of hundred students is as follows:student s[100];
In the above statement, s is an array of type student structure. The size of the array is hundred and the index will be from 0 to 99. If we have to access the name of first student, the first element of the array will be as under:
s[0].name;
Here s is the array so the index belongs to s. Therefore the first student is s[0], the 2nd student is s[1] and so on. To access the data members of the structure, the dot operator is used. Remember that the array index is used with the array name and not with the data member of the structure.
Sizeof operator
The sizeof operator is used to determine the size of data type. The sizeof operator can also be used with the structure. Structure contains different data types. How can we determine its size in the memory? Consider the student structure that contains two char arrays and two int data types. We can simply use the sizeof operator to determine its size. It will tell us how many bytes the structure is occupying.sizeof(s1);
We don’t need to add the size of all the data members of the structure. This operator is very useful while using the write() function to write the structure in the file.
Lesson 40: Unions
|
We have another construct named
union. The concept of union in C/C++ is: if we have something in the memory, is
there only one way to access that memory location or there are other ways to
access it. We have been using int and char interchangeably in our programs. Is
it possible to have a memory location and use it as int or char
interchangeably? For such purposes, the construct union is used. The syntax of
union is:
union intOrChar{
int i,
char c;
};
int i,
char c;
};
The syntax is similar as that of
structure. In structures, we have different data members and all of these have
their own memory space. In union, the memory location is same while the first
data member is one name for that memory location. However, the 2nd data member
is another name for the same location and so on.
Consider the above union (i.e.
intOrChar) that contains an integer and a character as data members. What will
be the size of this union? The answer is very simple. The union will be
allocated the memory equal to that of the largest size data member. If the int
occupies four bytes on our system and char occupies one byte, the union
intOrChar will occupy four bytes. Consider another example:
union intOrDouble{
int ival;
int ival;
double dval;
};
};
The above union has two data members
i.e. ival of type int and dval of type double. We know that double occupies
more memory space than integer. Therefore, the union will occupy the memory
space equivalent to double. The data members of unions are accessed in a
similar way as we use with structures i.e. using the dot operator. For example:
intOrDouble uval;
uval.ival = 10;
uval.ival = 10;
To get the output of the data
members, cout can be used as:
cout << “ The value in ival =
“ << uval.ival;
It will print “The value in ival
= 10”. Now what will be output of the following statement?
cout << “ The value in dval =
“ << uval.dval;
We don’t know. The reason is that in
the eight bytes of double, integer is written somewhere. When we use integer,
it is printed fine. When we printed the double, the value of int will not be
displayed. Rather something else will be printed. Similarly in the following
statement i.e.
uval.dval = 100.0;
cout << “ The value in dval = “ << uval.dval;
cout << “ The value in dval = “ << uval.dval;
It will print the right value of
dval. The value of this double is written in such a way that it will not be
interpreted by the integer. If we try to print out ival, it will not display
100. Unions are little bit safer for integer and characters. But we have to
think in terms that where to store the value in memory. Unions are very
rarely used.
No comments:
Post a Comment