into the new array, and delete the old array. Savitch

Pointers
Main Memory
Byte #00000000
01110101
Byte #00000001
11000101
Byte #00000010
10010100
Byte #00000011
00010000
Byte #00000100
11011110
Byte #00000101
00111010
Byte #00000110
11001000
Byte #00000111
00110000
Byte #00001000
00000000
Byte #00001001
00000000
Byte #00001010
00000001
Byte #00001011
00000101
Byte #00001100
00100100
Byte #00001101
11110100
Byte #00001110
10101001
Byte #00001111
11010010


Savitch - Chapter 12
A pointer is the memory address
of a variable.
Suppose that x is an int variable that
has been placed at this memory location
(note that it’s assumed that an int value
requires 4 bytes of memory).
In this example, x has the binary value
00000000000000000000000100000101
(i.e., 261) and is located at byte #8 (i.e.,
binary address 00001000).
In the program that uses variable x, the
pointer to its memory location is
accessed by using the & operator: &x is
that pointer.
CS 150
173
Pointer Variables
A pointer can be stored in a variable.
If pointer variable p is declared as
follows:
int *p;
Then p gets the memory address value
(in this case 00001000) and the
program can access the int value at
that address by using the * operator:
*p is the int value (in this case 261).
Note that pointers to different types
of variables are not interchangeable
(e.g., if the following declarations
occur:
int *p;
float *q;
then p and q are both pointers but they
are not the same type of pointers!
Savitch - Chapter 12
CS 150
Main Memory
Byte #00000000
01110101
Byte #00000001
11000101
Byte #00000010
10010100
Byte #00000011
00010000
Byte #00000100
11011110
Byte #00000101
00111010
Byte #00000110
11001000
Byte #00000111
00110000
Byte #00001000
00000000
Byte #00001001
00000000
Byte #00001010
00000001
Byte #00001011
00000101
Byte #00001100
00100100
Byte #00001101
11110100
Byte #00001110
10101001
Byte #00001111
11010010


174
A Simple Example
#include <iostream.h>
void main()
{
int x = 25;
int y = 99;
int *p;
cout
cout
cout
cout
cout
cout
cout
<<
<<
<<
<<
<<
<<
<<
"x =
"&x =
"y =
"&y =
"p =
"*p =
endl;
// At this point, pointer p may be pointing to "illegal" memory!
"
"
"
"
"
"
<<
<<
<<
<<
<<
<<
p = &y;
x = y;
cout
cout
cout
cout
cout
cout
cout
<<
<<
<<
<<
<<
<<
<<
x
&x
y
&y
p
*p
<<
<<
<<
<<
<<
<<
endl;
endl;
endl;
endl;
endl;
endl;
// Now *p and y are located at the same place in memory.
// Now x and y have the same value, at different locations.
"x =
"&x =
"y =
"&y =
"p =
"*p =
endl;
"
"
"
"
"
"
<<
<<
<<
<<
<<
<<
x
&x
y
&y
p
*p
<<
<<
<<
<<
<<
<<
endl;
endl;
endl;
endl;
endl;
endl;
return;
}
Savitch - Chapter 12
CS 150
175
Another Simple Example
#include <iostream.h>
#include <iomanip.h>
void main()
{
double *p, *q;
double x = 1.357,
cout << " p = " <<
cout << "*p = " <<
cout << " q = " <<
cout << "*q = " <<
cout << endl;
y = -2.073;
p << endl;
setw(10) << *p << endl;
q << endl;
setw(10) << *q << endl;
p = &x; q = &y;
cout << setprecision(6);
cout.setf(ios::fixed);
cout << " p = " << p << endl;
cout << "*p = " << setw(10) << *p << endl;
cout << " q = " << q << endl;
cout << "*q = " << setw(10) << *q << endl;
cout << endl;
*p =
cout
cout
cout
cout
cout
5.432; *q = *p;
<< " p = " << p << endl;
<< "*p = " << setw(10) << *p << endl;
<< " q = " << q << endl;
<< "*q = " << setw(10) << *q << endl;
<< endl;
*q =
cout
cout
cout
cout
cout
-8.246; p = q;
<< " p = " << p << endl;
<< "*p = " << setw(10) << *p << endl;
<< " q = " << q << endl;
<< "*q = " << setw(10) << *q << endl;
<< endl;
return;
}
x = 0.002; y = 9.999;
cout << " p = " << p << endl;
cout << "*p = " << setw(10) << *p << endl;
cout << " q = " << q << endl;
cout << "*q = " << setw(10) << *q << endl;
cout << endl;
Savitch - Chapter 12
CS 150
176
The new and delete Operators
#include <iostream.h>
The new operator sets up space in
memory that is adequate to hold a
dynamic variable of the designated
type (in this case int).
void main()
{
int *ptr;
cout << " ptr = " << ptr << endl;
cout << "*ptr = " << *ptr << endl;
cout << endl;
This ensures that the pointer has a
value that is in the valid portion of
the machine’s memory.
ptr = new int;
cout << " ptr = " << ptr << endl;
cout << "*ptr = " << *ptr << endl;
cout << endl;
*ptr
cout
cout
cout
= 1776;
<< " ptr = " << ptr << endl;
<< "*ptr = " << *ptr << endl;
<< endl;
delete ptr;
cout << " ptr = " << ptr << endl;
cout << "*ptr = " << *ptr << endl;
cout << endl;
return;
}
Savitch - Chapter 12
The delete operator returns the allocated
memory of the dynamic variable to the
system’s memory heap
Note that the pointer is still pointing to the
location in memory that it was originally
assigned in memory, but the memory at that
location is now available for other aspects of
the program and/or system.
CS 150
177
The new and delete Operators
#include <iostream.h>
void main()
{
char *pointerA;
char *pointerB;
cout << "*pointerA = " << '\'' << *pointerA << '\'' << endl;
cout << "*pointerB = " << '\'' << *pointerB << '\'' << endl;
cout << endl;
pointerA = new char;
*pointerA = 'Z';
pointerB = pointerA;
cout << "*pointerA = " << '\'' << *pointerA << '\'' << endl;
cout << "*pointerB = " << '\'' << *pointerB << '\'' << endl;
cout << endl;
delete pointerA;
pointerB = NULL;
if (pointerA == NULL)
cout << "pointerA is
else
cout << "*pointerA =
if (pointerB == NULL)
cout << "pointerB is
else
cout << "*pointerB =
cout << endl;
NULL" << endl;
" << '\'' << *pointerA << '\'' << endl;
NULL is a pointer value
that is used to signify
that the dynamic
variable associated
with the pointer has no
value.
Note that the use of
the NULL value is
preferable to leaving
the pointer “dangling”,
i.e., not knowing where
the pointer is pointing
or what it’s pointing to.
NULL" << endl;
" << '\'' << *pointerB << '\'' << endl;
return;
}
Savitch - Chapter 12
CS 150
178
What About Parameter Passing?
#include <iostream.h>
void reset(int *pp, int qq, int &rr, int *xx, int yy, int &zz);
void main()
The values of the pointer
{
arguments p and &x will be
int *p, *q, *r;
int x = 1, y = 1, z = 1;
placed in the corresponding
p = new
q = new
r = new
*p = *q
cout <<
cout <<
cout <<
cout <<
cout <<
cout <<
cout <<
int;
int;
int;
= *r = 1;
" p = " << p << " *p = " << *p << endl;
" q = " << q << " *q = " << *q << endl;
" r = " << r << " *r = " << *r << endl;
"&x = " << &x << " x = " << x << endl;
"&y = " << &y << " y = " << y << endl;
"&z = " << &z << " z = " << z << endl;
endl;
reset(p, *q, *r, &x, y, z);
cout
cout
cout
cout
cout
cout
cout
<<
<<
<<
<<
<<
<<
<<
" p =
" q =
" r =
"&x =
"&y =
"&z =
endl;
"
"
"
"
"
"
<< p << " *p = " << *p << endl;
<< q << " *q = " << *q << endl;
<< r << " *r = " << *r << endl;
<< &x << " x = " << x << endl;
<< &y << " y = " << y << endl;
<< &z << " z = " << z << endl;
pointer parameters pp and xx.
The values of the integer
arguments *q and y will be
placed in the corresponding
integer parameters qq and yy,
which are passed by value.
The locations of the integer
arguments *r and z will be
placed in the corresponding
pointer variables &rr and &zz,
since the integer parameters
rr and zz are passed by
reference.
return;
}
Savitch - Chapter 12
CS 150
179
What About Parameter Passing? (Part Two)
void reset(int *pp,
{
cout << " pp = "
cout << "&qq = "
cout << "&rr = "
cout << " xx = "
cout << "&yy = "
cout << "&zz = "
cout << endl;
int qq, int &rr, int *xx, int yy, int &zz)
<<
<<
<<
<<
<<
<<
pp
&qq
&rr
xx
&yy
&zz
<<
<<
<<
<<
<<
<<
" *pp = " << *pp << endl;
" qq = " << qq << endl;
" rr = " << rr << endl;
" *xx = " << *xx << endl;
" yy = " << yy << endl;
" zz = " << zz << endl;
*pp = qq = rr = *xx = yy = zz = 9;
cout
cout
cout
cout
cout
cout
cout
<<
<<
<<
<<
<<
<<
<<
" pp =
"&qq =
"&rr =
" xx =
"&yy =
"&zz =
endl;
"
"
"
"
"
"
<<
<<
<<
<<
<<
<<
pp
&qq
&rr
xx
&yy
&zz
<<
<<
<<
<<
<<
<<
" *pp = " << *pp << endl;
" qq = " << qq << endl;
" rr = " << rr << endl;
" *xx = " << *xx << endl;
" yy = " << yy << endl;
" zz = " << zz << endl;
return;
}
As expected, the functions changes to parameters *pp,
rr, *xx, and zz cause corresponding changes in their
main counterparts, since they share memory locations.
Changes to parameters qq and yy, however, do not alter
the values of their counterparts, since they don’t share
memory locations.
Savitch - Chapter 12
CS 150
180
Static Variables
#include <iostream.h>
void testStatic(int value);
void main()
{
testStatic(5);
return;
}
Recall that
variables that are
declared to be
static in a
function will
continue to exist
until the program
finishes, regardless
of when the
function finishes.
Also take note of the fact that
the function testStatic is
recursive, and that each
recursive call reserves its own
memory for variables value
and zippy.
void testStatic(int value)
{
static int count = 1;
int zippy = 1;
if (value == 0)
return;
else
{
cout << "&count = " << &count << " "
<< "count = " << count << endl;
cout << "&value = " << &value << " "
<< "value = " << value << endl;
cout << "&zippy = " << &zippy << " "
<< "zippy = " << zippy << endl;
cout << endl;
count++;
zippy++;
testStatic(value-1);
}
return;
}
Savitch - Chapter 12
CS 150
181
Array Variables
#include <iostream.h>
#include <iomanip.h>
void main()
{
double a[5] = {0.12345, 1.12345, 2.12345, 3.12345, 4.12345};
cout.setf(ios::fixed);
cout << setprecision(9);
cout << "
a = " << a << " ";
cout << "
*a = " << *a << endl;
cout << endl;
for (int i = 0; i <= 4; i++)
{
cout << "&a[" << i << "] = " << &a[i]
cout << " a[" << i << "] = " << a[i]
}
Note that an array variable is
a pointer, pointing to the
memory location of the first
indexed element in the array.
<< " ";
<< endl;
cout << endl;
return;
}
Savitch - Chapter 12
CS 150
182
Dynamic Arrays
Previously, array sizes had to be decided when you wrote the program.
With pointers, an array can be dynamic, with its size determined during
the program’s execution.
#include <iostream.h>
#include <iomanip.h>
Note that
the size of
the array is
not specified
until this
point in the
program.
void main()
{
typedef int* IntPtr;
IntPtr intList;
int listSize;
cout << "How big is the list? ";
cin >> listSize;
intList = new int[listSize];
for (int i = 0; i < listSize; i++)
{
intList[i] = i;
cout << setw(2) << intList[i]
<< ' ' << &intList[i] << endl;
}
cout << endl;
delete [] intList;
return;
}
Savitch - Chapter 12
The use of
the square
brackets
causes the
entire
dynamic
array to be
deleted.
CS 150
183
Making The SortedList Class Dynamic
// sortedList.h //
#ifndef SORTED_LIST_H
#include <iostream>
#include <string>
#include "phoneListing.h"
using namespace std;
typedef PhoneListing elementType;
typedef elementType* elementTypePtr;
class SortedList
{
public:
SortedList();
SortedList(int newLength);
SortedList(const SortedList &srtLst);
New type definition to
make it easier to set up
the entry data member
as a dynamic array.
New initializing constructor that
sets entry array up to have the
parameterized length.
int getLength() const;
elementType& operator [ ] (int position);
SortedList& operator = (const SortedList &srtLst);
bool insert(elementType elt);
The use of
bool remove(elementType elt);
bool retrieve(elementType elt, int &position);the square
private:
elementTypePtr entry;
int length;
int Index(int position) const;
bool binarySearch(int firstPosition, int
};
#define SORTED_LIST_H
#endif
Savitch - Chapter 12
brackets
the
Thecauses
revised
entry
entire
data
member.
dynamic
lastPosition, elementType
array to be
deleted.
CS 150
soughtElt, int &position);
184
The Modified Constructors & Assignment Operator
// This initializing constructor sets up the SortedList as one with no elements. //
SortedList::SortedList(int newLength)
{
length = newLength;
entry = new elementType[newLength];
}
// This copy constructor sets up the *this SortedList //
// as a duplicate of the parameterized SortedList.
//
SortedList::SortedList(const SortedList &lst)
{
length = lst.getLength();
entry = new elementType[length];
for (int i = 1; i <= length; i++)
entry[Index(i)] = lst.entry[Index(i)];
}
// The assignment operator gives the *this SortedList duplicate //
// values for each data member in the parameterized List. //
SortedList& SortedList::operator = (const SortedList &srtLst)
{
length = srtLst.getLength();
entry = new elementType[length];
for (int i = 1; i <= length; i++)
entry[Index(i)] = srtLst.entry[Index(i)];
return *this;
}
Savitch - Chapter 12
CS 150
The array length
is dynamically
determined in the
initializing and
copy constructors,
and in the
assignment
operator.
185
The Modified insert & remove Member Functions
// This member function inserts the parameterized //
// element into the *this SortedList.
//
To increase the length of the array,
bool SortedList::insert(elementType elt)
create another dynamic array that’s one
{
int position, i;
unit larger, copy the old array and the
retrieve(elt, position);
newly inserted element into the new
length++;
array, and delete the old array.
elementTypePtr tempEntry;
tempEntry = new elementType[length];
for (i = 1; i < position; i++)
// This member function removes the element
//
tempEntry[Index(i)] = entry[Index(i)];
// at the parameterized position from the *this //
tempEntry[Index(position)] = elt;
// SortedList (if the position is kosher).
//
for (i = position+1; i <= length; i++)
bool SortedList::remove(elementType elt)
tempEntry[Index(i)] = entry[Index(i-1)]; {
if (length > 1)
int position, i;
delete [] entry;
if (!retrieve(elt, position))
entry = tempEntry;
return false;
return true;
else
}
{
length--;
elementTypePtr tempEntry;
tempEntry = new elementType[length];
for (i = 1; i < position; i++)
tempEntry[Index(i)] = entry[Index(i)];
for (i = position+1; i <= length; i++)
tempEntry[Index(i-1)] = entry[Index(i)];
delete [] entry;
entry = tempEntry;
return true;
To decrease the length of the array,
create another dynamic array that’s one
unit smaller, copy the old array (except
for the element being removed) into the
new array, and delete the old array.
}
}
Savitch - Chapter 12
CS 150
186
Another Dynamic Array Example
// This program file tests whether the SortedList class effectively destroys old objects. //
#include <iostream.h>
#include <fstream.h>
#include "sortedList.h"
void loadFileWithName(char fileName[], elementTypePtr &eltPtr);
// The main function repeatedly calls a function that //
// loads a SortedList, and outputs the SortedList's
//
// elements (which should have been destroyed).
//
void main()
// Load a SortedList from a file. //
{
void loadFileWithName(char fileName[],
int soughtValue = 0;
elementTypePtr &eltPtr)
int count = 0;
{
elementTypePtr ptrA, ptrB, ptrC, ptrD, ptrE;
ifstream file;
SortedList list;
loadFileWithName("fileA.txt", ptrA);
int val;
loadFileWithName("fileB.txt", ptrB);
loadFileWithName("fileC.txt", ptrC);
loadFileWithName("fileD.txt", ptrD);
loadFileWithName("fileE.txt", ptrE);
for (int i = 0; i < 25; i++)
cout << ptrA[i] << ' ' << ptrB[i] << ' '
<< ptrC[i] << ' ' << ptrD[i] << ' ’
<< ptrE[i] << endl;
cout << endl;
return;
file.open(fileName);
file >> val;
while (!file.eof())
{
list.insert(val);
file >> val;
}
file.close();
eltPtr = &list[1];
return;
}
}
Savitch - Chapter 12
CS 150
187
Dynamic Arrays Can Waste Memory!
When run on the SortedList class
(modified to be a list of integers),
the driver program wastes memory
with each call to the subroutine.
While the SortedList variable is not
completely destroyed when the
function terminates, because the
dynamic aspect of the entry data
member hasn’t been taken into
account.
All versions of the entry data member are
being retained in memory!
Of course, they’ll all be freed up when the
program terminates, but, in the meantime,
the memory heap could get filled!
Savitch - Chapter 12
CS 150
188
Destructors Solve The Problem!
By defining a destructor member function for the SortedList class, we can
ensure that a SortedList object’s memory is completely returned to the
heap once it’s out of scope (i.e, once the function using it has terminated).
The destructor is called for a SortedList variable as the function returns.
// Destructor
~SortedList();
// The destructor function
// dereferences the entire
// entry array.
SortedList::~SortedList()
{
delete [] entry;
}
Notice that every memory
location has been given a
“value” that indicates that
it’s back in the heap!
Savitch - Chapter 12
CS 150
189
Copy Constructors
A copy constructor creates a new object of the
designated class, and needs to ensure that the new
object is independent of the original being copied.
The length data member is
// This copy constructor sets up the *this SortedList //
an integer, not a pointer, so
// as a duplicate of the parameterized SortedList.
//
SortedList::SortedList(const SortedList &lst)
the newly constructed
{
SortedList is merely given
length = lst.getLength();
a copy of its value.
entry = new elementType[length];
for (int i = 1; i <= length; i++)
entry[Index(i)] = lst.entry[Index(i)];
}
The entry data member is actually a
pointer, so we definitely don’t want the
newly constructed SortedList to be
given a copy of its value.
Savitch - Chapter 12
CS 150
190
What If There Was No Copy Constructor?
// This program file tests what happens when the //
// SortedList class has no copy constructor.
//
#include <iostream.h>
#include <fstream.h>
#include "sortedList.h"
void loadList(SortedList srtList, int newVal);
// The main function loads a SortedList twice, //
// and outputs the SortedList's elements.
//
void main()
{
SortedList list;
int i;
for (i = 1; i <= 5; i++)
list.insert(0);
for (i = 1; i <= 5; i++)
cout << list[i] << ' ';
cout << endl << endl;
loadList(list, 4321);
for (i = 1; i <= 5; i++)
cout << list[i] << ' ';
cout << endl << endl;
return;
}
// Load a SortedList with //
// a specific value.
//
void loadList(SortedList srtList,
int newVal)
{
for (int i = 1; i <= 5; i++)
srtList[i] = newVal;
return;
}
If there is a
destructor, the
original SortedList
is marked as “free
memory” by the
destructor!.
If there’s no destructor, then the subroutine’s assigned
values appear in the original SortedList!
Savitch - Chapter 12
CS 150
191
Assignment Operators
Similarly, when an overloaded assignment operator duplicates
an object of the designated class, it needs to ensure that the
duplicate and original are independent of each other.
The length data
// The assignment operator gives the *this SortedList duplicate //
// values for each data member in the parameterized List. //
member is an integer,
SortedList& SortedList::operator = (const SortedList &srtLst)
not a pointer, so the
{
*this SortedList is
length = srtLst.getLength();
merely given a copy of
entry = new elementType[length];
its value.
for (int i = 1; i <= length; i++)
entry[Index(i)] = srtLst.entry[Index(i)];
return *this;
The entry data member is actually a
}
pointer, so we definitely don’t want the
*this SortedList to be given a copy of
its value.
Notice the strong similarity between the assignment operator’s
code and the copy constructor’s code.
They’re identical, except for the return *this in the assignment
operator, which is required to enable assignment cascading.
Savitch - Chapter 12
CS 150
192