|
|||||
CS201
Introduction to Programming
Lecture
Handout
Introduction
to Programming
Lecture
No. 14
Reading
Material
Deitel
& Deitel - C++ How to
Program
Chapter
5
5.1,
5.2, 5.3, 5.4,
5.5,
5.6
Summary
1)
Pointers
2)
Declaration of
Pointers
3)
Example 1
(Bubble Sort)
4)
Pointers
and Call By Reference
5)
Example
2
Pointers
In the
earlier lectures, we had 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,
we request someone to take a
parcel to the house of a
person, named Ahmad.
Here the
point of reference is a name.
However, if we specifically tell
him the number of
house
and the street number.
Then this is a reference by
the address of the house.
It
means
that we have two ways to
locate an address. To understand further
the concept of
memory
address, the example of the
computers can be helpful. In
computers, one can
have a
name x
which is
associated with a memory location. We
can have the
memory
address
of x, say
6000 or whatever it is. So the simple
variable names are those
of
specific
locations in memory. But in terms of
addresses, these are the
addresses of those
memory
locations. We can use these
names and addresses
interchangeably to refer to
memory
locations. When a value is referred by a
normal variable is known as direct
reference.
While the value referred
through the use of memory
address may be known
as
indirect
reference.
To
understand further the terms of direct
reference and indirect
reference, suppose
that
we want
to assign a value 10 to x. This
can be done by
writing
x =
10. In
this
statement,
the value 10 will be
assigned to the memory
location which has label
(name) x.
The
second way to assign a value
to a memory location is with
reference to the address
of
Page
150
CS201
Introduction to Programming
that
memory location. In other words,
`assign a value to the
memory location whose
address
is contained in the variable (that is a
pointer) on right hand side of
the assignment
operator'.
Operators are used to refer
the address of memory locations
and to refer the
values at
those addresses.
Following
figure shows directly and
indirectly referencing a variable.
x
directly references
xptr
indirectly references a variable
whose
value is
10
xptr
x
a variable
whose value is 10
x
10
10
Now we
will try to comprehend the
concept with another daily
life 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
dais.
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
Page
151
CS201
Introduction to Programming
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
;
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.
The
following
figure shows a schematic representation
of memory after the
preceding
assignment
is executed.
x
ptr
1
The
pointers contain whole numbers as
they contain memory addresses. An
address can
be
represented only in whole
numbers. Therefore, a pointer is a whole
number, sufficient
enough,
to hold any memory address
of the computer. The pointers
have no specific data
type.
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.
The
following example can explain
the representation of the pointer in
memory. Assume
that
variable x is stored at location 400000
and pointer variable ptr
is
stored at location
Page
152
CS201
Introduction to Programming
500000.
ptr
x
400000
10
Address:
500000
400000
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 ;
Here *ptr
gives
the value stored at memory
address where the pointer ptr
points
to.
We know
that it is a good programming
practice to initialize a variable when we
declare
it.
This will ensure that
there will be no unknown
value in the variable at some
later
stage.
Similarly,
we should assign an initial
value to a pointer after declaring it.
Taking the
address
of a variable and assigning it to the
pointer is one way of initializing a
pointer. A
pointer
can be initialized by assigning
either value 0 or the word
NULL. The NULL is a
global
variable declared in many header files
that we include at the start of
the program.
The
pointer initialized by NULL as ptr
= NULL; is called
null pointer which points to
nothing.
Similarly, when we assign a
zero to a pointer like ptr
= 0;
it means that the
pointer is
pointing to nothing at the moment. Here
zero is not considered as a
valid
address
for a memory location. However, at
some later stage, we use
the pointer in an
assignment
statement either on left
hand side to assign a value to it or as a
part of an
expression
on right hand side. The
pointer must have a valid memory
address where a
value
should have stored. We get
the address of a variable by putting
& operator before
the
name of the variable and
assign it to a pointer as in the
following statement ptr
= &x;
We know
that 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
void fn (
int *num)
{
Page
153
CS201
Introduction to Programming
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).
Example
(Bubble Sort)
You
might be knowing the
technique of bubble sorting. Its
application helps us compare
two
values each time and
interchange the larger and
smaller values. In this way, we
sort
the
arrays. To interchange the
position of larger and smaller
value, the technique
of
swapping is
used. Swapping is very
common in programming. While
using this
technique,
we put value of one variable in a
temporary location to preserve it and
assign
the
value of second variable to the
first. Then the temporary
value is assigned to
the
second
variable.
Suppose,
we want to swap the values
of two variables x
and
y. For
this purpose, a third
variable temp is
used in the following
fashion.
temp = x
;
x=y;
y = temp
;
We can
write the above three
statements in a program to swap the
value of x and y. Now
the
question arises, can we call
a function swap (x, y) which
has a code to swap
the
values of
x and y. We call the
function swap by passing x
and
y. When
the control comes
back to
the calling function, the
values of x
and
y
are
the same as before. These
are not
Page
154
CS201
Introduction to Programming
swapped.
This is mainly due to the
fact that passing value to
function swap is a call by
value. It
does not change the values
in the calling function. The
swap function receives a
copy of
the values and interchanges
the values in that copy. The
original values remain
the
same.
To
interchange two values in a
function, we make a call by
reference to the
function.
Here
comes the use of pointers.
To write the swap function to
interchange two
values
always
use pointers in the function
to get the swapped values in
the calling function.
The
code
fragment in our main program
will be written as
follows:
yptr =
&y ;
//
address of y is stored in
yptr
xptr =
&x ;
//
address of x is stored in
xptr
swap
(yptr, xptr) ;
//
addresses are passed
The
receiving function must know that
addresses are being passed
to it. So the
declaration
of swap function will
be:
swap
(int *yptr, int
*xptr)
{
.........
}
This
use of pointers implements a
call by reference. We can
use this technique in
bubble
sort.
The swap function can switch
the elements of the array by
using pointers and *
operator.
The
code of the program that
sorts an array by bubble
sort and use the swap
function to
interchange
the elements of the array is
given here.
/*
This
program uses bubble sorting to sort a
given array.
*
We use
swap function to interchange the
values by using
pointers
*/
#include
<iostream.h>
#include
<stdlib.h>
/* Prototye of
function swap used to swap
two values */
void
swap(int *, int *) ;
main()
{
int x []
= {1,3,5,7,9,2,4,6,8,10};
int i, j,
tmp, swaps;
for(i =
0; i < 10; i ++)
{
swaps =
0;
for(j =
0; j < 10; j ++)
Page
155
CS201
Introduction to Programming
{
if ( x[j]
> x[j+1])
//
compare two values and
interchange if needed
{
swaps++;
swap(&x[j],&x[j+1]);
}
}
//display
the array's elements after
each comparison
for
(j=0; j<10; j++)
cout
<< x[j] << '\t';
cout
<< endl;
if (swaps
== 0)
break;
}
}
void
swap(int *x, int *y)
//function
using pointers to interchange
the values
{
int
tmp;
if(*x
> *y)
{
tmp =
*x;
*x =
*y;
*y =
tmp;
}
}
Following
is the output of the program
of bubble sort.
1
3
5
7
2
4
6
8
9
10
1
3
5
2
4
6
7
8
9
10
1
3
2
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
Pointers and
Call By Reference
Suppose,
we have a function that performs a
specific task again and
again but with
different
variables each time. One
way to do this is to pass a
different variable to the
Page
156
CS201
Introduction to Programming
function,
each time, by reference. We
can also write the
function with pointers. In
this
case,
before calling the function,
put the address of the
simple variable in the pointer
variable
and pass it to the function.
This is a call by reference.
Thus the same pointer
variable
can be used each time by
assigning it the address of a
different variable.
The
mechanism behind calling a function is
that, when we call a
function we pass it
some
variables.
The values of these
variables are used with in
the function. In call by
value
mechanism,
the values of these
variables are written
somewhere else in the
memory. That
means a
copy of these values is made.
Then control goes to the
called function and
this
copy of
values is used in the
function. If we have to pass a
huge number of values to
a
function,
it is not advisable to copy these
huge numbers of values. In
such cases, it is
better to
pass the reference of the
variables, which is a call by
reference phenomenon. We
perform a
similar function in case of an
array, where we can pass,
say, 100 values (size
of
the
array) to the called function, by
only passing the name of
the array. When we pass
an
array to
a function, actually the starting
address of the array is
passed to the
function.
Thus
the default calling mechanism to call a
function while passing an
array to it is a call
by
reference.
The
problem with call by
reference is that `we are
letting the function to
change the
values at
their actual storage place in
the memory'. Sometimes, we want to do
this
according
to the requirement of the
logic of the program. At
some other occasion,
we
may
pass the addresses for
efficiency while not
affecting the values at that
addresses. The
use of
const can be helpful in overcoming
this problem..
Let's
look at the use of const.
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 constant pointers is
not much useful.
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
Page
157
CS201
Introduction to Programming
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.
Example
2
Let's
consider an example in which we use
the pointers to make a call
by reference.
We want
to convert the lowercase letters of a
string (character array), to their
corresponding
uppercase letters.
We write
a function convertToUppercase, which
processes the string s one
character at a
time
using pointer arithmetic. In the body of
the function, we pass the
character to a
function
islower. This function
returns true if the
character is a lowercase letter and
false
otherwise.
The characters in the range
`a' through `z' are
converted to their
corresponding
uppercase letters by function
toupper. Function toupper takes
one
character
as an argument. If the character is a
lowercase letter, the
corresponding
uppercase
letter is returned, otherwise the
original character is returned.
The functions
toupper
and islower are part of
the character handling library
<ctype.h>. So we have to
include
this header file in our
program. We include it in the
same way, as we include
<iostream.h>.
The
complete code of the program is given
below.
//This
program converts a string into an
uppercase string
# include
<iostream.h>
# include
<ctype.h>
# include
<stdlib.h>
//declare
the functions prototype
void
convertToUppercase (char *)
main
()
{
Page
158
CS201
Introduction to Programming
char s
[30] = "Welcome To Virtual
University" ;
cout
<< "The string before conversion
is: " << s << endl ;
convertToUppercase
( s) ;
//function
call
cout
<< "The string after conversion
is: " << s ;
}
void
convertToUppercase (char
*sptr)
{
while (
*sptr != `\0' )
{
if (
islower ( *sptr) )
*sptr =
toupper ( *sptr );
//convert to
uppercase
++
sptr;
// move
sptr to the next
character
}
}
Following
is the output of the
program.
The
string before conversion is :
Welcome
To
The
string after conversion is :
WELCOME
TO
Exercise
1.
Modify
the above program so that it
gets a string from user and
converts it into
lowercase.
2.
Write a
program, which converts a string of
uppercase letters into its
corresponding
lowercase
letters string.
Page
159
Table of Contents:
|
|||||