Transcript
Page 1: Savitch - Chapters 9&11 CS 150173 Pointers A pointer holds the memory address of a variable. Main Memory Byte #00000000 Byte #00000001 Byte #00000010 Byte

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.

Page 2: Savitch - Chapters 9&11 CS 150173 Pointers A pointer holds the memory address of a variable. Main Memory Byte #00000000 Byte #00000001 Byte #00000010 Byte

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!

Page 3: Savitch - Chapters 9&11 CS 150173 Pointers A pointer holds the memory address of a variable. Main Memory Byte #00000000 Byte #00000001 Byte #00000010 Byte

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;}

Page 4: Savitch - Chapters 9&11 CS 150173 Pointers A pointer holds the memory address of a variable. Main Memory Byte #00000000 Byte #00000001 Byte #00000010 Byte

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;}

Page 5: Savitch - Chapters 9&11 CS 150173 Pointers A pointer holds the memory address of a variable. Main Memory Byte #00000000 Byte #00000001 Byte #00000010 Byte

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.

Page 6: Savitch - Chapters 9&11 CS 150173 Pointers A pointer holds the memory address of a variable. Main Memory Byte #00000000 Byte #00000001 Byte #00000010 Byte

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.

Page 7: Savitch - Chapters 9&11 CS 150173 Pointers A pointer holds the memory address of a variable. Main Memory Byte #00000000 Byte #00000001 Byte #00000010 Byte

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.

Page 8: Savitch - Chapters 9&11 CS 150173 Pointers A pointer holds the memory address of a variable. Main Memory Byte #00000000 Byte #00000001 Byte #00000010 Byte

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.

Page 9: Savitch - Chapters 9&11 CS 150173 Pointers A pointer holds the memory address of a variable. Main Memory Byte #00000000 Byte #00000001 Byte #00000010 Byte

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.

Page 10: Savitch - Chapters 9&11 CS 150173 Pointers A pointer holds the memory address of a variable. Main Memory Byte #00000000 Byte #00000001 Byte #00000010 Byte

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.

Page 11: Savitch - Chapters 9&11 CS 150173 Pointers A pointer holds the memory address of a variable. Main Memory Byte #00000000 Byte #00000001 Byte #00000010 Byte

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.

Page 12: Savitch - Chapters 9&11 CS 150173 Pointers A pointer holds the memory address of a variable. Main Memory Byte #00000000 Byte #00000001 Byte #00000010 Byte

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.

Page 13: Savitch - Chapters 9&11 CS 150173 Pointers A pointer holds the memory address of a variable. Main Memory Byte #00000000 Byte #00000001 Byte #00000010 Byte

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.

Page 14: Savitch - Chapters 9&11 CS 150173 Pointers A pointer holds the memory address of a variable. Main Memory Byte #00000000 Byte #00000001 Byte #00000010 Byte

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.

Page 15: Savitch - Chapters 9&11 CS 150173 Pointers A pointer holds the memory address of a variable. Main Memory Byte #00000000 Byte #00000001 Byte #00000010 Byte

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;}

Page 16: Savitch - Chapters 9&11 CS 150173 Pointers A pointer holds the memory address of a variable. Main Memory Byte #00000000 Byte #00000001 Byte #00000010 Byte

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!

Page 17: Savitch - Chapters 9&11 CS 150173 Pointers A pointer holds the memory address of a variable. Main Memory Byte #00000000 Byte #00000001 Byte #00000010 Byte

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!

Page 18: Savitch - Chapters 9&11 CS 150173 Pointers A pointer holds the memory address of a variable. Main Memory Byte #00000000 Byte #00000001 Byte #00000010 Byte

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.

Page 19: Savitch - Chapters 9&11 CS 150173 Pointers A pointer holds the memory address of a variable. Main Memory Byte #00000000 Byte #00000001 Byte #00000010 Byte

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!.

Page 20: Savitch - Chapters 9&11 CS 150173 Pointers A pointer holds the memory address of a variable. Main Memory Byte #00000000 Byte #00000001 Byte #00000010 Byte

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.


Top Related