savitch - chapters 9&11 cs 150173 pointers a pointer holds the memory address of a variable....
Embed Size (px)
TRANSCRIPT

Savitch - Chapters 9&11
CS 150 1
Pointers
A pointer holds the memory address of a variable.
Main MemoryByte #00000000
Byte #00000001
Byte #00000010
Byte #00000011
Byte #00000100
Byte #00000101
Byte #00000110
Byte #00000111
Byte #00001000
Byte #00001001
Byte #00001010
Byte #00001011
Byte #00001100
Byte #00001101
Byte #00001110
Byte #00001111
01110101
11000101
10010100
00010000
11011110
00111010
11001000
00110000
00000000
00000000
00000001
00000101
00100100
11110100
10101001
11010010
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.

Savitch - Chapters 9&11
CS 150 2
Pointer Variables
A pointer can be stored in a variable. Main MemoryByte #00000000
Byte #00000001
Byte #00000010
Byte #00000011
Byte #00000100
Byte #00000101
Byte #00000110
Byte #00000111
Byte #00001000
Byte #00001001
Byte #00001010
Byte #00001011
Byte #00001100
Byte #00001101
Byte #00001110
Byte #00001111
01110101
11000101
10010100
00010000
11011110
00111010
11001000
00110000
00000000
00000000
00000001
00000101
00100100
11110100
10101001
11010010
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 - Chapters 9&11
CS 150 3
A Simple Example#include <iostream>using namespace std;
void main(){ int x = 25; int y = 99; int *p; // At this point, pointer p may be pointing to "illegal" memory!
cout << "x = " << x << endl; cout << "&x = " << &x << endl; cout << "y = " << y << endl; cout << "&y = " << &y << endl; cout << "p = " << p << endl; cout << "*p = " << *p << endl; cout << endl;
p = &y; // Now *p and y are located at the same place in memory. x = y; // Now x and y have the same value, at different locations.
cout << "x = " << x << endl; cout << "&x = " << &x << endl; cout << "y = " << y << endl; cout << "&y = " << &y << endl; cout << "p = " << p << endl; cout << "*p = " << *p << endl; cout << endl;
return;}

Savitch - Chapters 9&11
CS 150 4
Another Simple Example#include <iostream>#include <iomanip>using namespace std;
void main(){ double *p, *q; double x = 1.357, y = -2.073; cout << " p = " << p << endl; cout << "*p = " << setw(10) << *p << endl; cout << " q = " << q << endl; cout << "*q = " << setw(10) << *q << endl; cout << 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;
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;
*p = 5.432; *q = *p; cout << " p = " << p << endl; cout << "*p = " << setw(10) << *p << endl; cout << " q = " << q << endl; cout << "*q = " << setw(10) << *q << endl; cout << endl;
*q = -8.246; p = q; cout << " p = " << p << endl; cout << "*p = " << setw(10) << *p << endl; cout << " q = " << q << endl; cout << "*q = " << setw(10) << *q << endl; cout << endl;
return;}

Savitch - Chapters 9&11
CS 150 5
The new and delete Operators#include <iostream>using namespace std;
void main(){ int *ptr; cout << " ptr = " << ptr << endl; cout << "*ptr = " << *ptr << endl; cout << endl;
ptr = new int; cout << " ptr = " << ptr << endl; cout << "*ptr = " << *ptr << endl; cout << endl;
*ptr = 1776; cout << " ptr = " << ptr << endl; cout << "*ptr = " << *ptr << endl; cout << endl;
delete ptr; cout << " ptr = " << ptr << endl; cout << "*ptr = " << *ptr << endl; cout << endl;
return;}
The new operator sets up space in memory that is adequate to hold a dynamic variable of the designated type (in this case
int).
This ensures that the pointer has a value that is in the valid
portion of the machine’s memory.
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.

Savitch - Chapters 9&11
CS 150 6
The new and delete Operators#include <iostream>using namespace std;
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 NULL" << endl; else cout << "*pointerA = " << '\'' << *pointerA << '\'' << endl; if (pointerB == NULL) cout << "pointerB is NULL" << endl; else cout << "*pointerB = " << '\'' << *pointerB << '\'' << endl; cout << endl;
return;}
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.

Savitch - Chapters 9&11
CS 150 7
What About Parameter Passing?#include <iostream>using namespace std;void reset(int *pp, int qq, int &rr, int *xx, int yy, int &zz);void main(){ int *p, *q, *r; int x = 1, y = 1, z = 1;
p = new int; q = new int; r = new int; *p = *q = *r = 1; cout << " p = " << p << " *p = " << *p << endl; cout << " q = " << q << " *q = " << *q << endl; cout << " r = " << r << " *r = " << *r << endl; cout << "&x = " << &x << " x = " << x << endl; cout << "&y = " << &y << " y = " << y << endl; cout << "&z = " << &z << " z = " << z << endl; cout << endl;
reset(p, *q, *r, &x, y, z);
cout << " p = " << p << " *p = " << *p << endl; cout << " q = " << q << " *q = " << *q << endl; cout << " r = " << r << " *r = " << *r << endl; cout << "&x = " << &x << " x = " << x << endl; cout << "&y = " << &y << " y = " << y << endl; cout << "&z = " << &z << " z = " << z << endl; cout << endl;
return;}
The values of the pointer arguments p and &x will be placed in the corresponding
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.

Savitch - Chapters 9&11
CS 150 8
What About Parameter Passing? (Part Two)
void reset(int *pp, int qq, int &rr, int *xx, int yy, int &zz){ cout << " pp = " << pp << " *pp = " << *pp << endl; cout << "&qq = " << &qq << " qq = " << qq << endl; cout << "&rr = " << &rr << " rr = " << rr << endl; cout << " xx = " << xx << " *xx = " << *xx << endl; cout << "&yy = " << &yy << " yy = " << yy << endl; cout << "&zz = " << &zz << " zz = " << zz << endl; cout << endl;
*pp = qq = rr = *xx = yy = zz = 9;
cout << " pp = " << pp << " *pp = " << *pp << endl; cout << "&qq = " << &qq << " qq = " << qq << endl; cout << "&rr = " << &rr << " rr = " << rr << endl; cout << " xx = " << xx << " *xx = " << *xx << endl; cout << "&yy = " << &yy << " yy = " << yy << endl; cout << "&zz = " << &zz << " zz = " << zz << endl; cout << 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 - Chapters 9&11
CS 150 9
Static Variables#include <iostream>using namespace std;
void testStatic(int value);
void main()
{ testStatic(5); return;}
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); }}
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.

Savitch - Chapters 9&11
CS 150 10
Array Variables
#include <iostream>#include <iomanip>using namespace std;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] << endl; } cout << endl; return;}
Note that an array variable is a pointer, pointing to the
memory location of the first indexed element in the
array.

Savitch - Chapters 9&11
CS 150 11
Dynamic Arrays
#include <iostream>#include <iomanip>using namespace std;
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;
}
Note that the size of the array is
not specified until this
point in the program.
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.
The use of the square brackets
causes the entire
dynamic array to be
deleted.

Savitch - Chapters 9&11
CS 150 12
Making The SortedList Class Dynamic
The use of the square brackets
causes the entire
dynamic array to be
deleted.
// 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(const SortedList &srtLst); int getLength() const; elementType& operator [ ] (int position); SortedList& operator = (const SortedList &srtLst); bool insert(elementType elt); bool remove(elementType elt); bool retrieve(elementType elt, int &position);
private: elementTypePtr entry; int length;
int Index(int position) const; bool binarySearch(int firstPosition, int lastPosition, elementType soughtElt, int &position);};#define SORTED_LIST_H#endif
New type definition to make it easier to set up the entry data
member as a dynamic array.
The revised entry data member.

Savitch - Chapters 9&11
CS 150 13
The Modified Constructors & Assignment Operator
// 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){ if(entry == srtLst.entry) return *this; delete [] entry; length = srtLst.getLength(); entry = new elementType[length]; for (int i = 1; i <= length; i++) entry[Index(i)] = srtLst.entry[Index(i)]; return *this;}
The array length is
dynamically determined
in the initializing and copy
constructors, and in the assignment operator.

Savitch - Chapters 9&11
CS 150 14
The Modified insert & remove Member Functions// This member function inserts the parameterized //// element into the *this SortedList. //bool SortedList::insert(elementType elt){ int position, i; retrieve(elt, position); length++; elementTypePtr tempEntry; tempEntry = new elementType[length]; for (i = 1; i < position; i++) tempEntry[Index(i)] = entry[Index(i)]; tempEntry[Index(position)] = elt; for (i = position+1; i <= length; i++) tempEntry[Index(i)] = entry[Index(i-1)]; if (length > 1) delete [] entry; entry = tempEntry; return true;}
// This member function removes the element //// at the parameterized position from the *this //// SortedList (if the position is kosher). //bool SortedList::remove(elementType elt){ int position, i; if (!retrieve(elt, position)) return false; else { length--; elementTypePtr tempEntry; tempEntry = new elementType[length]; for (i = 1; i < position; i++) tempEntry[Index(i)] = entry[Index(i)]; for (i = position; i <= length; i++) tempEntry[Index(i)] = entry[Index(i+1)]; delete [] entry; entry = tempEntry; return true; }}
To increase the length of the array, create another dynamic
array that’s one unit larger, copy the old array and the newly
inserted element into the new array, and delete the old array.
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 - Chapters 9&11
CS 150 15
Another Dynamic Array Example// This program file tests whether the SortedList class effectively destroys old objects. //
#include <iostream>#include <fstream>#include <string>#include "sortedList.h"using namespace std;
void loadFileWithName(string 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(){ int soughtValue = 0; int count = 0; elementTypePtr ptrA, ptrB, ptrC, ptrD, ptrE;
loadFileWithName("fileA.txt", ptrA); 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;}
// Load a SortedList from a file. //void loadFileWithName(string fileName, elementTypePtr &eltPtr){ ifstream file; SortedList list; int val;
file.open(fileName.c_str()); file >> val; while (!file.eof()) { list.insert(val); file >> val; } file.close();
eltPtr = &list[1]; return;}

Savitch - Chapters 9&11
CS 150 16
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 - Chapters 9&11
CS 150 17
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(){ if(length > 0) delete [] entry;}
Notice that every memory location has been given a “value”
that indicates that it’s back in the heap!

Savitch - Chapters 9&11
CS 150 18
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.
// 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 length data member is an integer, not a pointer, so the newly constructed SortedList is merely given a copy of its
value.
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 - Chapters 9&11
CS 150 19
What If There Was No Copy Constructor?// This program file tests what happens when the //// SortedList class has no copy constructor. //
#include <iostream>#include <fstream>#include "sortedList.h" using namespace std;
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’s no destructor, then the subroutine’s assigned values appear in the
original SortedList!
If there is a destructor, the
original SortedList is
marked as “free memory” by the
destructor!.

Savitch - Chapters 9&11
CS 150 20
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 assignment operator gives the *this SortedList duplicate //// values for each data member in the parameterized List. //SortedList& SortedList::operator = (const SortedList &srtLst){ if(entry == srtLst.entry) return *this; delete [] entry; length = srtLst.getLength(); entry = new elementType[length]; for (int i = 1; i <= length; i++) entry[Index(i)] = srtLst.entry[Index(i)]; return *this;}
The length data member is an integer, not a pointer, so the
*this SortedList is merely given a
copy of its value.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.