|
|||||
CS201
Introduction to Programming
Lecture
Handout
Introduction
to Programming
Lecture
No. 15
Reading
Material
Deitel
& Deitel - C++ How to
Program
Chapter
5
5.7,
5.8
Summary
6)
Introduction
7)
Relationship
between Pointers and
Arrays
8)
Pointer
Expressions and
Arithmetic
9)
Pointers
Comparison
10)
Pointer,
String and Arrays
11)
Tips
Introduction
In the
previous lecture, we had just
started the discussion on
the topic of pointers.
This
topic is
little complicated, yet the power we
get with the pointers is
very interesting. We
can do
many interesting things with pointers.
When other languages like
Java evolve with
the
passage of time, pointers
are explicitly excluded. In today's
lecture, we will
discuss
pointers,
the relationship between pointers
and arrays, pointer expressions,
arithmetic
with
pointers, relationship between arrays
and pointer, strings
etc.
Relationship
between 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"
Page
160
CS201
Introduction to Programming
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;
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
+ 4). 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
Page
161
CS201
Introduction to Programming
//
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;
}
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
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). To display the contents where
the yptr
is
pointing we
can
use cout
with
dereference pointer as:
cout
<< *yptr ;
Page
162
CS201
Introduction to Programming
The
above statement will display
the contents where yptr
is
pointing. If the yptr
is
pointing
to the first element of the
array, cout
<< *yptr will
display the contents of
the
first
element of the array (i.e.
y[0]). While incrementing the
yptr
as
yptr
++, the
statement
cout
<< * yptr will
display the contents of the 2nd element of the
array(i.e.
y[1])
and so on.
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
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.
The
following example can explain
how we can step through an
entire array using
pointer.
/* This
program steps through an
array using pointer */
#include
<iostream.h>
Page
163
CS201
Introduction to Programming
main
()
{
int
y[10] = {10,20,30,40,50,60,70,80,90,100};
int
*yptr, i;
yptr = y;
// Assigning the address of
first element of
array.
for (i =
0; i < 10 ; i ++)
{
cout
<< "\n The value of
the element at position " << i
<< " is " << *yptr;
yptr ++
;
}
}
The
output of the program is:
The
value of the element at
position 0 is 10
The
value of the element at
position 1 is 20
The
value of the element at
position 2 is 30
The
value of the element at
position 3 is 40
The
value of the element at
position 4 is 50
The
value of the element at
position 5 is 60
The
value of the element at
position 6 is 70
The
value of the element at
position 7 is 80
The
value of the element at
position 8 is 90
The
value of the element at
position 9 is 100
Consider
another example to elaborate the pointer
arithmetic.
/*
Program using pointer arithmetic
*/
#include
<iostream.h>
main()
{
int x
=10;
int
*yptr;
yptr =
&x;
cout
<< "The address yptr points to = "
<< yptr << endl ;
cout
<< "The contents yptr points to = "
<< *yptr << endl;
Page
164
CS201
Introduction to Programming
(*yptr)
++;
cout
<< "After increment, the contents
are " << *yptr <<
endl;
cout
<< "The value of x is = " << x <<
endl;
}
The
output of the program is:
The
address yptr points to =
0x22ff7c
The
contents yptr points to = 10
After
increment, the contents are
11
The
value of x is = 11
Here the
statement (*yptr)
++ is
read as "increment whatever yptr
points
to". This will
increment
the value of the variable. As
yptr
and
x
both
are pointing to the same
location,
the
contents at that location
becomes 11. Consider the
statement *yptr
+ 3 ; This is
an
expression
and there is no assignment so
the value of x will not be
changed where as the
statement
*yptr
+= 3; will
increment the value of x
by 3.
If we want to increment the
pointer
and not the contents where
it points to, we can do this as yptr
++; Now
where
yptr
is
pointing? The yptr
will be
now pointing four bytes
away from the
memory
location
of x. The
memory location of x
is a
part of program, yet after incrementing
yptr,
it is
pointing to some memory
area, which is not part of
the program. Take this as
an
exercise.
Print the value of yptr
and
*yptr
and
see what is displayed? Be
sure, it is not
illegal
and the compiler does
not complain. The error
will be displayed if we try to
write
some
value at that memory
address.
"When a
pointer is used to hold the
memory address of a simple variable, do
not
increment or
decrement the pointer. When a pointer is
used to hold the address
of
an array,
it makes sense to increment or decrement
the pointer "
Be careful
while using pointers, as no
warning will be given, in case of
any problem. As
pointers
can point at any memory
location, so one can easily get
the computers crashed
by using
pointers.
Remember
that incrementing the pointer and
incrementing the value where the
pointer
points to
are two different things. When we
want to increment the pointer, to make
it
point to
next element in the memory,
we write as (yptr++);
Use
parenthesis when
incrementing
the address. If we want to increment
the value where the pointer points to,
it
can be
written as (*yptr)
++; Keep in
mind the precedence of
operator. Write a program
to test
this.
The
decrement of the pointer is also
the same. yptr
--;
yptr
-= 3 ; will
decrement the yptr.
Whereas
the statement (*yptr)
--; will
decrement the value where
the yptr
is
pointing. So
if the
yptr
is
pointing to x
the
value of x
will be
decremented by 1.
Page
165
CS201
Introduction to Programming
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. If we move
to some
other architecture like
Macintosh, write a simple
program to check how
many
bytes
integer, float or char is
taking with the use of
simple pointer arithmetic. In
the
modern
operating systems like
windows XP, windows 2000,
calculator is provided under
tools
menu. Under the view option,
select scientific view. Here we
can do hexadecimal
calculations. So we
can key in the addresses
our programs are displaying
on the screen
and by
subtracting, we can see the
difference between the two
addresses. Try to
write
different
programs and experiment with
these.
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 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.
Consider
the following sample
program:
/*
Program using the pointer
subtraction */
#include
<iostream.h>
main
()
{
int
y[10], *yptr1,
*yptr2;
yptr1 =
&y[0];
yptr2 =
&y[3];
cout
<< " The difference = " << yptr2 -
yptr1;
}
The
output of the program is:
Page
166
CS201
Introduction to Programming
The
difference = 3
In the
above program, we have taken
two integer pointers yptr1
and
yptr2
and an
integer
array
y[10]. The
pointer yptr1
is
pointing to the address of
the first element of the
array
while
yptr2
is
pointing to the 4th element of the array.
The difference between these
two
pointers
can be shown by using cout
statement.
Here the result should be
twelve. But the
program
will show the result as
three. When we increment an integer pointer by 1,
we
have
seen that the address is
changed by four. When we subtract
pointers, it tells us
the
distance
between the two elements
that the pointers pointed
to. It will tell us how
many
array
elements are between these
two pointers. As the yptr1
is
pointing to y[0]
and
the
yptr2
is
pointing to y[3], so the
answer is three. In a way, it
tells how many units of
data
type
(pointers data type) are
between the two pointers.
Pointer addition is not
allowed,
however, pointer
subtraction is allowed as it gives the
distance between the two
pointers
in units,
which are the same as
the data type of the
pointer.
A memory
image of an array with a pointer.
Addresses: 3000
3004
3008
3012
3016
y[0]
y[1]
y[2]
y[3]
y[4]
yptr
yptr++
yptr
This
diagram shows how an array occupies
space in the memory.
Suppose, we have an
integer
array named y
and
yptr
is a
pointer to an integer and is assigned
the address of the
first
element of the array. As
this is an integer array, so
the difference between
each
element
of the array is of four
bytes. When the yptr
is
incremented, it starts pointing
to
the
next element in the
array.
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 using
Page
167
CS201
Introduction to Programming
two
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.
Make a list what
can
we do
with a pointer and what we
cannot.
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
";
}
}
The
output of the program is;
Please
enter the value of x =
6
Please
enter the value of y =
9
Page
168
CS201
Introduction to Programming
y is
greater than x
Pointer,
String 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' ;
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.
Page
169
CS201
Introduction to Programming
"Arrays
must be at least one character
space larger than the
number of printable
characters
which are to be stored"
Example:
Write a
program which copies a character
array into given
array.
Solution:
Here is
the complete code of the
program:
/* 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 */
}
The
output of the program is:
String in
strA = A test string
String in
strB = A test string
Page
170
CS201
Introduction to Programming
Explanation:
Suppose,
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. We can
also write a
function
for the string copy. The prototype of
the function will be
as:
void
myStringCopy (char *destination,
const char *source) ;
This
function takes two
arguments. The first one is
a pointer to a char while
second
argument
is a const pointer to char. The
destination array will be
changed and all
the
characters
from source array are
copied to destination. At the
same time, we do not
want
that
the contents of source
should be changed. So we used
the keyword const with
it. The
keyword
const makes it read only
and it can not be changed
accidentally. If we try to
change
the contents of source
array, the compiler will
give an error. The body is
same, as
we have
seen in the above
program.
This
function will not return
anything as we are using pointers. It is
automatically call by
reference.
Whenever arrays are passed
to functions, a reference of the original
array is
passed.
Therefore, any change in the
array elements in the
function will change the
actual
array.
The values will be written
to the original array. If
these are simple variables,
we
will
have to send the address
and get the called program
to change it. Therefore, we
do
not
need to return anything from
this function after successfully
copying an array into
the
other.
Here is
the code of the function.
Write a program to test this
function.
Page
171
CS201
Introduction to Programming
void
myStringCopy (char *destination,
const char *source)
{
while(*source
!= `\0')
{
*destination++
= *source++;
}
*destination
= `\0';
}
We can
also write the string copy
function using arrays. Here is
the code of the
myStringCopy
function using arrays
notation.
void
myStringCopy(char dest[], char
source[])
{
int i =
0;
while
(source[i] != '\0')
{
dest[i] =
source[i];
i++;
}
dest[i] =
'\0';
}
Exercise:
1) Print
out the address and
the value of a character pointer
pointing to some
character.
2) Write
a function which copies an
array of integers from one
array to other
Tips
·
While
incrementing the pointers, use
the parenthesis
·
Increment
and decrement the pointers
while using arrays
·
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
·
Use key
word const with pointers to
avoid unwanted changes
·
The
name of array is a constant pointer. It
cannot be reassigned
Page
172
Table of Contents:
|
|||||