Transcript Document

Pointers and Dynamic Data
Textbook Chapter 15
1
Recall that . . .
char message[ 6 ] = “Hello”;
message is the base address of the array. We say message
is a pointer because its value is an address. It is a pointer
constant because the value of str itself cannot be changed by
assignment. It “points” to the memory location of a char.
6000
message
‘H’
‘e’
[0]
[1]
‘l’
[2]
‘l’
[3]
‘o’
[4]
‘\0’
[5]
2
Addresses in Memory
• when a variable is declared, enough memory to hold a
value of that type is allocated for it in an unused
memory location. This is the address of the variable
int
float
char
2000
x
x;
number;
ch;
2004
number
2008
ch
3
Obtaining Memory Addresses
• the address of a non-array variable can be obtained by
using the address-of operator &
int
float
char
x;
number;
ch;
cout << “Address of x is “ << &x << endl;
cout << “Address of number is “ << &number << endl;
cout << “Address of ch is “ << &ch << endl;
4
C++ Data Types
simple
integral
enum
structured
floating
array struct union class
char short int long bool
address
float double long double
pointer
reference
5
What is a pointer variable?
• A pointer variable is a variable whose value is the address
of a location in memory.
• to declare a pointer variable, you must specify the type of
value that the pointer will point to,for example
int
char
*ptr; // ptr will hold the address of an int
float
*q;
// q will hold the address of a char
*r, *s;
// r and s “point to” floats
6
Using a Pointer Variable
2000
int x;
x = 12;
12
x
int *ptr;
ptr = &x;
3000
2000
ptr
NOTE: Because ptr holds the address of x,
we say that ptr “points to” x
7
Unary operator * is the indirection
(deference) operator
2000
int x;
x = 12;
12
x
int *ptr;
ptr = &x;
cout
<<
3000
2000
ptr
*ptr;
NOTE: The value pointed to by ptr is denoted by *ptr
8
Using the Dereference Operator
int x;
x = 12;
2000
12
5
x
int *ptr;
ptr = &x;
*ptr = 5;
3000
2000
ptr
// changes the value
// at address ptr to 5
9
Another Example
char
ch =
ch;
‘A’;
char *q;
q = &ch;
*q = ‘Z’;
4000
A
ch
5000
6000
4000
q
char *p;
p = q;
Z
4000
p
// both pointers have the value 4000
// now p and q both point to ch
10
Using a Pointer to Access the
Elements of a C String
3000
char msg[ ] = “Hello”;
char* ptr;
‘M’ ‘a’
‘H’ ‘e’
‘l’
‘l’
‘o’
‘\0’
3000
3001
ptr
ptr = msg;
*ptr = ‘M’ ;
ptr++;
*ptr = ‘a’;
// recall that msg == &msg[ 0 ]
// Changes 3000 to ‘M’
// increments the address in ptr
// Changes 3001 to ‘a’
11
int StringLength ( /* in */ const char str[ ] )
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Precondition: str is a null-terminated string
// Postcondition: FCTVAL == length of str (not counting ‘\0’)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {
char* p ;
int count = 0;
p = str;
while ( *p != ‘\0’ ) {
count++ ;
p++ ;
// increments the address p by sizeof char
}
return count;
}
12
12
The NULL Pointer
There is a pointer constant called the “null pointer”
denoted by NULL in header file cstddef.
NOTE: It is an error to dereference a pointer whose value
is NULL. Such an error may cause your program to
crash, or behave erratically. It is the programmer’s job
to check for this.
while (ptr != NULL) {
. . .
// ok to use *ptr here
}
13
Manipulating the Heap
• Most memory allocation is set up at compile
time, the compiler handles reserving and
freeing memory, and the memory footprint
is fixed during execution.
• The Heap is a pool of memory which is
available at run time, operating system
handles reserving and freeing this memory.
14
3 Kinds of Program Data
• STATIC DATA: memory allocation exists throughout
execution of program (global variables or by using the
static keyword)
static long currentSeed;
• AUTOMATIC DATA: automatically created at
function entry, resides in activation frame of the
function, and is destroyed when returning from
function
• DYNAMIC DATA: explicitly allocated and deallocated
during program execution by C++ instructions written
by programmer using operators new and delete
15
Allocation of Memory
STATIC and AUTOMATIC ALLOCATION
DYNAMIC
ALLOCATION
Allocation of
memory space at
compile time.
Dynamic
allocation is the
allocation of
memory space at
run time by using
operator new.
16
Operator new Syntax
new DataType;
new DataType [IntExpression];
If memory is available, in the heap new allocates the
requested object or array, and returns a pointer to
(address of ) the memory allocated.
Otherwise, program terminates with an error message.
The dynamically allocated object exists until the delete
operator destroys it.
17
Dynamically Allocated Data
char*
ptr;
2000
ptr
ptr = new char;
*ptr = ‘B’;
cout
<<
*ptr;
18
Dynamically Allocated Data
char*
ptr;
ptr = new char;
2000
ptr
*ptr = ‘B’;
cout
<<
*ptr;
NOTE: Dynamic data has no variable name
19
Dynamically Allocated Data
2000
char*
ptr;
ptr = new char;
ptr
*ptr = ‘B’;
cout
<<
‘B’
*ptr;
NOTE: Dynamic data has no variable name
20
Dynamically Allocated Data
char*
ptr;
2000
?
ptr
ptr = new char;
*ptr = ‘B’;
cout
delete
<<
*ptr;
ptr;
NOTE: delete
deallocates
the memory
pointed to
by ptr
21
Operator delete Syntax
delete Pointer;
delete [ ] Pointer;
If the value of the pointer is NULL there is no effect.
Otherwise, the object or array currently pointed to by
Pointer is deallocated, and the value of Pointer
becomes undefined. The memory is returned to the
heap.
Square brackets are used with delete to deallocate a
dynamically allocated array.
22
Dynamic Array Allocation
char *ptr;
// ptr is a pointer variable that
// can hold the address of a char
ptr = new char[ 5 ];
// dynamically, during run time, allocates
// memory for a 5 character array
// and stores the base address into ptr
6000
6000
ptr
23
Dynamic Array Allocation
char *ptr ;
ptr = new char[ 5 ];
strcpy( ptr, “Bye” );
ptr[ 1 ] = ‘u’;
// a pointer can be subscripted
cout << ptr[ 2] ;
6000
6000
‘B’
‘u’
‘y’
‘e’
‘\0’
ptr
24
Dynamic Array Deallocation
char *ptr ;
ptr = new char[ 5 ];
strcpy( ptr, “Bye” );
ptr[ 1 ] = ‘u’;
delete [ ] ptr; // deallocates array pointed to by ptr
// ptr itself is not deallocated
// the value of ptr is undefined.
?
ptr
25
Run-Time Size Determination
char *ptr ;
int desiredsize;
cout<<“Please enter an integer:”;
cin>>desiredsize;
ptr = new char[ desiredsize ];
Overcomes limitation of static arrays…
26
What happens here?
int* ptr = new int;
*ptr = 3;
3
ptr
ptr = new int;
*ptr = 4;
// changes value of ptr
3
ptr
4
NOTE: dynamic data has no name since the
27
Compiler did not assign an identifier to it
Inaccessible Object
An inaccessible object is an unnamed object that was
created by the operator new which a programmer has
left without a pointer to it.
int* ptr = new int;
*ptr = 8;
int* ptr2 = new int;
*ptr2 = -5;
8
ptr
-5
ptr2
How else can an object become inaccessible?
28
Making an Object Inaccessible
int* ptr = new int;
*ptr = 8;
int* ptr2 = new int;
*ptr2 = -5;
8
ptr
-5
ptr2
ptr = ptr2;
// here the 8 becomes inaccessible
8
ptr
-5
ptr2
29
Memory Leak
A memory leak is the loss of available memory space
that occurs when dynamic data is allocated but
never deallocated.
30
A Dangling Pointer
is a pointer that points to dynamic memory that has
been deallocated
•
int* ptr = new int;
*ptr = 8;
int* ptr2 = new int;
*ptr2 = -5;
ptr = ptr2;
8
ptr
-5
ptr2
FOR EXAMPLE,
31
Leaving a Dangling Pointer
int* ptr = new int;
*ptr = 8;
int* ptr2 = new int;
*ptr2 = -5;
ptr = ptr2;
8
ptr
-5
ptr2
8
delete ptr2;
// ptr is left dangling
ptr2 = NULL;
ptr
NULL
ptr2
32
Dynamic Array Class
• As an example of a class that uses dynamic
storage, we will develop a dynamic array class
• Static arrays have the limitation that you must
know the size at compile time:
int scores[100];
• Our class will allow dynamic allocation:
// Calculate how many you need in scoreSize
DynArray scores(scoreSize);
33
class DynArray
Heap
DynArray
~DynArray
Private data:
DynArray
size
ValueAt
arr
5
6000
80
40
6000
90
Store
?
CopyFrom
?
34
//
//
//
//
SPECIFICATION FILE
(dynarray.h)
Safe integer array class allows run-time specification
of size, prevents indexes from going out of bounds,
allows aggregate array copying and initialization.
class DynArray {
public:
DynArray( /* in */ int arrSize );
// Constructor.
// PRE: arrSize is assigned
// POST: IF arrSize >= 1 && enough memory THEN
//
Array of size arrSize is created with
//
all elements == 0 ELSE error message.
DynArray(DynArray& otherArr );
// Copy constructor.
// POST: this DynArray is a deep copy of otherArr
// Is implicitly called for initialization.
35
// SPECIFICATION FILE
continued
(dynarray.h)
~DynArray( );
// Destructor.
// POST: Memory for dynamic array deallocated.
int
ValueAt ( /* in */ int i );
// PRE: i is assigned.
// POST: IF 0 <= i < size of this array THEN
//
FCTVAL == value of array element at index i
//
ELSE error message.
void
Store ( /* in */ int val, /* in */ int i );
// PRE: val and i are assigned
// POST: IF 0 <= i < size of this array THEN
//
val is stored in array element i
//
ELSE error message.
36
36
// SPECIFICATION FILE
void
continued
(dynarray.h)
CopyFrom ( /* in */ DynArray otherArr);
// POST: IF enough memory THEN
//
new array created (as deep copy)
//
with size and contents
//
same as otherArr
//
ELSE error message.
private:
int* arr ;
int
size ;
};
37
37
DynArray beta(5); //constructor
beta
Heap
DynArray
~DynArray
Private data:
DynArray
size
ValueAt
arr
5
2000
?
?
2000
?
Store
?
CopyFrom
?
38
DynArray::DynArray( /* in */
int arrSize )
// Constructor.
// PRE: arrSize is assigned
// POST: IF arrSize >= 1 && enough memory THEN
//
Array of size arrSize is created with
//
all elements == 0 ELSE error message.
{
int i;
if ( arrSize < 1 ) {
cerr << “DynArray constructor - invalid size: “
<< arrSize << endl;
exit(1);
}
arr = new
int[arrSize] ;
// allocate memory
size = arrSize;
for (i = 0; i < size;
arr[i] = 0;
}
i++)
39
39
beta.Store(75, 2);
beta
Heap
DynArray
~DynArray
DynArray
ValueAt
Private data:
size
5
2000
?
?
arr
2000
75
Store
?
CopyFrom
?
40
void
DynArray::Store ( /* in */ int val,
/* in */ int i )
// PRE: val and i are assigned
// POST: IF 0 <= i < size of this array THEN
//
arr[i] == val
//
ELSE error message.
{
if ( i < 0 || i >= size ) {
cerr << “Store - invalid index : “ << i << endl;
exit(1) ;
}
arr[i] = val ;
}
41
41
DynArray gamma(4);
gamma
beta
DynArray
~DynArray
DynArray
DynArray
Private:
size
4
3000
?
?
ValueAt
arr 3000
Private:
~DynArray
DynArray
ValueAt
?
Store
5
?
?
arr 2000
75
Store
?
CopyFrom
size
2000
?
CopyFrom
?
42
gamma.Store(-8,2);
gamma
beta
DynArray
DynArray
Private:
~DynArray
DynArray
ValueAt
size
4
3000
?
?
arr 3000
Private:
~DynArray
DynArray
ValueAt
-8
Store
5
?
?
arr 2000
75
Store
?
CopyFrom
size
2000
?
CopyFrom
?
43
int
DynArray::ValueAt ( /* in */ int i )
// PRE:
// POST:
//
//
i is assigned.
IF 0 <= i < size THEN
FCTVAL == arr[i]
ELSE halt with error message.
{
if ( i < 0 || i >= size ) {
cerr << “ValueAt - invalid index : “ << i <<
endl;
exit(1) ;
}
return
arr[i];
}
44
44
Why is a destructor needed?
When a DynArray class variable goes out of scope, the
memory space for data members size and pointer
arr is deallocated.
But the dynamic array that arr points to is not
automatically deallocated.
A class destructor is used to deallocate the dynamic
memory pointed to by the data member.
45
Without destructor…
Instance “beta” memory is freed by garbage collector…
Heap
Private data:
size
2000
?
?
arr
75
?
?
…dynamic data from heap is left with no pointer!
46
class DynArray Destructor
DynArray::~DynArray( )
// Destructor.
// POST: Memory for dynamic array deallocated.
{
delete [ ] arr ;
}
47
47
What happens . . .
• When a function is called that uses pass by value for a
class object of DynArray type?
DynArray
~DynArray
DynArray
Private:
size
5
2000
?
?
ValueAt
arr 2000
75
Store
?
CopyFrom
?
48
Passing a Class Object by Value
// FUNCTION CODE
void SomeFunc( DynArray someArr )
// Uses pass by value, instance memory is copied
{
.
.
.
.
}
49
49
By default,
Pass-by-value makes a shallow copy
DynArray beta(5);
// CLIENT CODE
SomeFunc( beta );
// function call
.
.
.
beta
someArr
2000
DynArray
Private:
.
.
.
size
5
arr 2000
?
?
75
DynArray
Private:
.
.
.
size
5
arr 2000
?
?
shallow copy
50
Shallow Copy vs. Deep Copy
• a shallow copy copies only the class data
members, and does not make a copy of any
pointed-to data
•
a deep copy copies not only the class data
members, but also makes a separate stored
copy of any pointed-to data
51
What’s the difference?
• a shallow copy shares the pointed to
dynamic data with the original class object
•
a deep copy makes its own copy of the
pointed to dynamic data at different
locations than the original class object
52
Making a (Separate) Deep Copy
beta
2000
DynArray
.
.
.
Private:
?
size
?
5
arr 2000
75
?
?
someArr
4000
DynArray
.
.
.
Private:
?
size
?
5
75
arr 4000
?
?
deep copy
53
Initialization of Class Objects
• C++ defines initialization to mean
•
–
initialization in a variable declaration
–
passing an object argument by value
–
returning an object as the return value of a
function
by default, C++ uses shallow copies for these
initializations
54
As a result . . .
• when a class has a data member pointer to
dynamically allocated data, you should write what
is called a copy constructor
• the copy constructor is implicitly called in
initialization situations and makes a deep copy of
the dynamic data in a different memory location
55
More about Copy Constructors
•
when there is a copy constructor provided for a
class, the copy constructor is used to make copies
for pass by value
•
you do not call the copy constructor
•
like other constructors, it has no return type
•
because the copy constructor properly defines pass
by value for your class, it must use pass by
reference in its definition
56
Copy Constructor
• copy constructor is a special member function of a class
that is implicitly called in these 3 situations:
– passing object parameters by value
– initializing an object variable in its declaration
– returning an object as the return value of a function
57
SomeFunc(beta); // copy-constructor
// beta passed by value
beta
someArr
DynArray
DynArray
Private:
~DynArray
DynArray
size
5
2000
?
?
ValueAt
arr 2000
Private:
~DynArray
DynArray
ValueAt
size
5
?
?
arr 4000
75
Store
4000
75
Store
?
CopyFrom
?
CopyFrom
?
?
DEEP COPY
58
Suppose SomeFunc calls Store
// FUNCTION CODE
void SomeFunc( DynArray someArr )
// Uses pass by value
{
someArr.Store(290, 2);
.
.
.
}
WHAT HAPPENS IN THE SHALLOW COPY SCENARIO?
59
59
beta.arr[2] has changed
DynArray beta(5);
.
.
.
// CLIENT CODE
SomeFunc( beta);
beta
someArr
2000
DynArray
Private:
.
.
.
size
5
arr 2000
?
?
290
DynArray
Private:
.
.
.
size
5
arr 2000
?
?
shallow copy
60
beta.arr[2] has changed
NOTICE THAT NOT JUST FOR THE SHALLOW COPY,
BUT ALSO FOR ARGUMENT beta,
THE DYNAMIC DATA HAS CHANGED!
beta
someArr
2000
DynArray
Private:
.
.
.
size
5
arr 2000
?
?
290
DynArray
Private:
.
.
.
size
5
arr 2000
?
?
shallow copy
61
Classes with Dynamic Data Need
DEF. CONSTRUCTOR
COPY CONSTRUCTOR
DESTRUCTOR
What if you have one without the others?
62
DynArray::DynArray( /* in */
int arrSize )
// Constructor.
// PRE: arrSize is assigned
// POST: IF arrSize >= 1 && enough memory THEN
//
Array of size arrSize is created with
//
all elements == 0 ELSE error message.
{
int i;
if ( arrSize < 1 ) {
cerr << “DynArray constructor - invalid size: “
<< arrSize << endl;
exit(1);
}
arr = new
int[arrSize] ;
// allocate memory
size = arrSize;
for (i = 0; i < size;
arr[i] = 0;
}
i++)
63
63
Copy Constructor
• Needed when an object contains pointers
to dynamic data, AND
• You need each object to have its own
dynamic data
64
DynArray::DynArray( DynArray& otherArr )
// Copy constructor (copy from otherArr)
// Implicitly called for deep copy in initializations.
// POST: If room on free store THEN
//
new array of size otherArr.size is created
//
on free store && arr == its base address
//
&& size == otherArr.size
//
&& arr[0..size-1] == otherArr.arr[0..size-1]
//
ELSE error message.
{
int i ;
size = otherArr.size ;
arr = new int[size] ;
// allocate memory for copy
for ( i = 0; i< size ; i++ )
arr[i] = otherArr.arr[i] ;
// copies array
}
65
65
Destructor
• Automatically called when object goes
out of scope
• Required when creating dynamic data in
an object to free it
• Be careful when passing an object by
value:
• On return from function, the destructor
is called. If you did not have a copy
constructor, it will delete the caller’s
dynamic data
66
What about the assignment operator?
• the default method used for assignment of class
objects makes a shallow copy
•
if your class has a data member pointer to dynamic
data, you should write a member function to create a
deep copy of the dynamic data
67
gamma.CopyFrom(beta);
gamma
beta
DynArray
DynArray
Private:
~DynArray
DynArray
size
5
3000
?
?
arr 3000
ValueAt
Private:
~DynArray
DynArray
ValueAt
75
Store
size
5
2000
?
?
arr 2000
75
Store
?
CopyFrom
CopyFrom
?
DEEP COPY
?
?
68
void
DynArray::CopyFrom ( /* in */ DynArray otherArr )
// Creates a deep copy of otherArr.
// POST: Array pointed to by arr@entry deallocated
//
&& IF room on free store
//
THEN new array is created on free store
//
&& arr == its base address
//
&& size == otherArr.size
//
&& arr[0..size-1] == otherArr[0..size-1]
//
ELSE halts with error message.
{
int i ;
delete [ ] arr ;
size = otherArr.size ;
arr = new int [size] ;
for ( i = 0; i< size ; i++ )
arr[i] = otherArr.arr[i] ;
}
// delete current array
// allocate new array
// deep copy array
69
69
Functions and Pointers
• A pointer variable can be passed as a parameter
• Once you have a pointer, you can change the
caller’s variable that it is pointing to (same as
passing by reference)
void example(int* p)
{
*p = 0; // Changes caller’s variable
// pointed to by p
}
A function can return a value of type pointer
70
Classes, structs, and Pointer
Variables
• Pointers can be declared to point to class
and struct objects (instances)
71
Pointers to Structs
struct electric
{
string current;
int volts;
};
electric *p, *q;
• p and q are pointers to a struct of type
electric
72
Pointers to Structs
p = new electric;
• Allocates storage for struct of type electric
and places address into pointer p
p
current
?
volts
?
73
Classes, structs, and Pointer
Variables
• To simplify the accessing of class or struct
components via a pointer
– C++ provides the member access operator
arrow, ->
• The syntax for accessing a class (struct)
member using the operator -> is:
pointerVariableName->classMemberName
74
Pointer Dereferencing
and Member Selection
p
. current . volts
p
p
. current . volts
*p
p
. current . volts
(*p).current
p->current
75
75
struct Member Access through a
Pointer
p ->current = “AC”;
p ->volts = 115;
p
current
AC
volts
115
• Could also be referenced as
(*p).current = “AC”;
(*p).volts = 115;
76
Pointers and Structs
q = new electric;
• Allocates storage for struct of type electric
and places address into pointer q
• Copy contents of p struct to q struct
*q = *p;
p
current
AC
volts
115
q
current
AC
volts
115
77
Pointers and Structs
q ->volts = 220;
q
current
AC
volts
220
p->current
q->current
AC
p->volts
q->volts
115
AC
220
q = p;
p
q
78
Pointer to a Class Object
TimeType
time1;
TimeType* timeptr = &time1;
timeptr->set(12,0,0);
timeptr->increment();
… and so on
Any public member function can be accessed
via the pointer to its object
79
Pointer to array of objects…
// name is a class
name* nameptr = new name[5];
string someNames[5]={"A","B","C","D","E"};
for (int i = 0;i < 5; i++)
{
nameptr[i].set(someNames[i]);
}
80
Array of pointers to objects…
name* namePtrList[5];
for (int j = 0;j < 5; j++)
{
namePtrList[j] = new name;
namePtrList[j]->set(someNames[j]);
}
81
Common Programming Errors
• Common Syntax Errors
– Misuse of * , &, and ->
– Misuse of new and delete
• Common Run-Time Errors
– Memory Leak
• Forgot to deallocate dynamic memory…
– NULL Pointer Dereference
• Forgot to use NEW before accessing…
– Heap Overflow
• Ran out of room in the heap…
82
Summary
• Pointer variables contain the addresses of other
variables as their values
• Declare a pointer variable with an asterisk
between the data type and the variable
• & is called the “address of” operator
• & returns the address of its operand
• * is called the “dereference operator”
• * returns the target of its pointer operand
83
Summary
• The dereference member access operator arrow
accesses a component of an object pointed to by
a pointer
• Dynamic Variable: allocated during execution
• Operator new creates a dynamic variable
• Operator delete deallocates memory occupied by
a dynamic variable
• Dynamic array: created during execution
84
Summary
• Shallow copy: two or more pointers of the
same type point to the same memory
• Deep copy: two or more pointers of the same
type have their own copies of the data
85