08 Pointers
08 Pointers
08 Pointers
5)
8. Part I: Run-Time Arrays — Intro. to
Pointers
For declarations like
double doubleVar;
char charVar = 'A';
int intVar = 1234;
the compiler constructs the
object being declared, which
means that it:
1. Allocates memory needed 1234
for that A
type of object
2.
3. Associates the memory
Initializes that object's
name with
that memory
1
Addresses
& is the address operator in C++
&variable is the address (actual memory location) of variable
*dptr
Value of dptr: 0x7fffb7e8
Value of *dptr: 3.3
We say dptr points to that memory
4
location (whose address is 0x7fffb7e8)
Suppose we replace the preceding output
statements by:
cout << "i = " << *iptr << endl
<< "j = " << *jptr << endl
<< "d = " << *dptr << endl
(*iptr)++;
<< "e = " << *eptr << endl;
cout << "i = " << i << endl;
Output produced:
i = 11
j = 22
d = 3.3
i
e = 12
4.4
5
A Note About Reference Parameters:
Recall the C++ function to exchange the values of two int
variables:
void Swap(int & a, int & b)
{ int temp = a; a = b; b = temp; }
The values of two int variables x and y can be exchanged with
the call:
Swap(x,y);
The first C++ compilers were just preprocessors that read a C+
+ program, produced functionally equivalent C code, and ran it
through the C compiler. But C has no reference parameters.
How were they handled?
Translate the function to
void Swap(int * a, int * b)
{ int temp = *a; *a = *b; *b = temp; }
A reference parameter is a variable containing
and
the the preceding call to: Swap(&x, &y);
6
address of its argument (i.e., it's a pointer
This indicates how the call-by-reference parameter mechanism
Anonymous variables
Definitions:
A variable is a memory location.
A named variable has a name associated with its
memory location, so that this memory location can
be accessed conveniently.
An anonymous variable has no name associated
with its memory location; if the address of that
memory location
is stored in a pointer variable, then the variable
can be accessed indirectly using the pointer.
7
Named variables are created using a normal variable
declaration.
For example, the declaration
int j = 22;
i. constructed an integer (4-byte) variable at memory
address 0x7fffb7f0 and initialized those 4
bytes to the value 22; and
ii. associated the name j with that address, so that all
subsequent uses of j refer to address 0x7fffb7f0 ;
the
statement
cout << j << endl;
will display the 4-byte value (22) at address 8
0x7fffb7f0 .
new operator
Anonymous variables are usually created using the
new operator, whose form is:
new Type
*dptr = 3.14159;
*eptr = 0.1423;
cout << *dptr << " " << *eptr << endl;
dptr "Alias problem"
What’s
0.1423 output?
0.1423
eptr
12
Note 3: What if we changed this to:
double *dptr, *eptr;
dptr = new double;
*dptr = 3.14159;
*eptr = 0.1423;
new Type[n]
int numItems;
double dub[20]; // an ordinary compile-time array
double *dubPtr; // a pointer to a (run-time) array
cout << "How many numbers to process? "; cin >> numItems;
dubPtr = new double[numItems];
17
When the heap has been exhausted, new returns the value 0 (called the
null address or null pointer).
Common to picture a null pointer variable using the electrical engineering
ground symbol:
dptr
delete pointerVariable;
19
For run-time arrays, to return to the heap memory allocated to array pointed to
by arrayPtr. use the delete operator in the form
delete[] arrayPtr;
Important to do this because memory leaks involving arrays can result in
considerable loss of memory.
For example:
for(;;)
{
int n;
cout << "Size of array (0 to stop): ";
cin >> n;
if (n == 0) break;
double * arrayPtr = new double[n];
// process arrayPtr
. . .
}
Each new allocation of memory to arrayPtr maroons old memory block
20
new and delete for Class
Objects
If Type is a class, new Type will
i. Allocate memory
ii. Call Type's constructor to create a value
to use to initialize this memory block.
new can also be used in the form
new Type(initVal)
to call an explicit-value constructor.
int * ptr1 = new int; // integer allocated
*ptr1 = 103; // anonymous integer initialized
int * ptr2; // no integer allocated
ptr2 = new int(104); // anonymous integer allocated
// and initialized
If Type is a class, delete Type will
i. Call Type's destructor to destroy the object
in this memory block.
ii. Deallocate the memory 21
Run-time Allo-/Deallo-cation in a
Class
Classes that use run-time allocated storage require some new
function members and modifications of others:
1.Destructors: To "tear down" the storage structure and
deallocate its memory.
2.Copy constructors: To make copies of objects
(e.g., value parameters)
3. Assignment: To assign one storage structure to another.
22
Data Members
We will use a run-time allocated array so that the user can specify the capacity
of the stack during run time. We simply change the declaration of the
myArray member to a pointer and STACK_CAPACITY to a variable; to avoid
confusion, we will use different names for the data members.
24
template <typename StackElement>
Stack<StackElement>::Stack(int numElements)
{
assert (numElements > 0); // check precondition
myCapacity_ = numElements; // set stack capacity
// allocate array of this capacity
myArrayPtr = new StackElement[myCapacity_];
We must add a destructor member function to the class to avoid this memory
leak.
Destructor's role: Deallocate memory allocated at run-time
(the opposite of the constructor's role).
At any point in a program where an object goes out of scope,
the compiler inserts a call to this destructor.
That is:
~Stack();
// Following class declaration
// Definition of destructor
template <typename StackElement>
inline Stack<StackElement>::~Stack()
{
delete[] myArrayPtr; 29
}
Suppose st is
st
myCapacity_ 5
myTop_ 2
0 1 2 3 4
myArrayPtr a b c
In initializations
stCopy myCapacity_ 5
myTop_ 2
myArrayPtr
stCopy myCapacity_ 5
myTop_ 2 0 1 2 3 4 32
myArrayPtr a b c
Form of copy constructor:
It is a constructor so it must be a function member, its name is
the class name, and it has no return type.
It needs a single parameter (source of copy) whose type is
the class; this must be a reference parameter and should be
const since it does not change this parameter or pass
information
back through
(Otherwise it. be a value parameter, and since a value
it would
parameter is a copy of its argument, a call to the copy instructor
will try and copy its argument, which calls the copy constructor,
which will try and copy its argument, which calls the copy
constructor . . . )
/* --- Copy Constructor ---
* Precondition: A copy of a stack is needed
* Receive: The stack to be copied (as a const
* reference parameter)
* Postcondition: A copy of original has been constructed.
************************************************************/
35
Prototype:
36
Definition of operator=:
It is quite similar to that for the copy constructor, but there are
some differences:
1. Object on the left side of the assignment may already have a
value. Must
destroy old value — deallocate the old so no memory leak
—
and allocate a new one.
2. Assignment must be concerned with self-assignments: st =
st;.
Can't destroy the old value in this case.
Every
3. member function
operator=() of a the
must return class has access
Stack to a this
containing (hidden)
function.
pointer constant
For #3 we use the following
this property of classes:
whose value is the address of the object containing this
function.
The expression
*this 37
refers to the object itself.
template <typename StackElement>
Stack<StackElement> & Stack<StackElement>::operator=
(const Stack<StackElement> & original)
{
if ( this != &original ) // check that not st = st
{
delete[] myArrayPtr; // destroy previous array
40
Read (§8.1 & §8.2)
data
first 9 17 22 26 34
next
45
Basic Operations:
Construction: first = null_value first
Empty: first == null_value?
Traverse:
ptr = first;
while (ptr != null_value)
{
Process data part of node pointed to by ptr
ptr = next part of node pointed to by ptr;
}
46
first 9 17 22 26 34
ptr = first;
while (ptr != null_value)
{ ptr
Process data part of
node pointed to by ptr; first 9 17 22 26 34
ptr = next part of node
pointed to by ptr;
} ptr
.
.
.
first 9 17 22 26 34
ptr
first 9 17 22 26 34
ptr
47
Insert: To insert 20 after 17 in the preceding linked list
need address of item before point of insertion
predptr points to the node containing 17
(1) Get a new node pointed to by newptr and store 20 in it
predptr
first 9 17 22 29 34
20
newptr
(2) Set the next pointer of this new node equal to the next
pointer in its predecessor, thus making it point to its
successor. predptr
first 9 17 22 29 34
20
newptr
48
(3) Reset the next pointer of its predecessor to point to this new
node. predptr
first 9 17 22 29 34
20
newptr
55
newptr 49
Inserting at the beginning of the list requires a modification of
steps 2 and 3:
Example: Insert a node containing 5 at the beginning of the list.
(1) as before
(2) set next link to first node in the list
(3) set first to point to new node.
predptr
first 9 17 20 22 29 34 55
5
newptr
50
Delete: Delete node containing 22 from following list. Suppose
ptr points to the node to be deleted and predptr points to its
predecessor (the node containing 20)
predptr ptr
first 5 9 17 20 22 29 34
first 5 9 17 20 22 29 34
first 5 9 17 20 22 29 34
51
Same process works at the end of the list.
Example: Delete the node at the end of the
list.
(1) as before — sets next link to null pointer
predptr ptr free store
(2) as before
first 5 9 17 22 29 34
first 5 9 17 22 29
53
List-processing algorithms that require fast access to each
element cannot (usually) be done as efficiently with linked lists.
For nodes:
55
For free store:
const int NULL_VALUE = -1;
57
For the linked list operations:
Use node[p].data to access the data part of node pointed to by
p
Use node[p].next to access the next part of node pointed to by
p
Example: Traversal
Pointer p = first;
while (p != NULL_VALUE)
{
Process(node[p].data);
p = node[p].next;
}
58
Using C++ Pointers and Classes (§8.6)
To Implement Nodes
class Node
{
public:
DataType data;
Node * next;
};
59
How do we declare pointers, assign them, access contents of
nodes, etc.?
Declarations:
Node * ptr; or typedef Node * NodePointer;
NodePointer ptr;
60
Why make data members public in class Node?
This class declaration will be placed inside another class
declaration for LinkedList. The data members data and next
of struct Node will be public inside the class and thus will
accessible to the member and friend functions of the class, but
they will be private outside the class.
#ifndef LINKEDLIST
#define LINKEDLIST
template <typename DataType>;
class LinkedList
{
private: So why not just make
class Node Node a struct? We could,
{ but it is common
public:
DataType data; practice to use struct for
Node * next; C-style structs that
}; contain no functions
typedef Node * NodePointer; (and we will want to add
. . . a few to our Node class.)
}; 61
#endif
Data Members for LinkedList:
Linked lists like
first 9 17 22 26 34
mySize 5
63
Function Members for LinkedList:
L
first 9 17 22 26 34
mySize 5
marooned!
64
Copy constructor: Why is one needed? For the same reason
as for
run-time arrays.
If we don't provide one, the default copy constructor (which
just does a byte-by-byte copy) used by the compiler for a linked
list like L will produce:
L
first 9 17 22 26 34
mySize 5
copyOfL
first
mySize 5
65
Linked List Variants (§9.1)
last
mySize 5
first ? 9 17 22 26 34 ?
68
In other applications a circular linked list is used;
instead of the last node containing a null pointer, it
contains a pointer to the first node in the list.
For such lists,one can use a single pointer to the
last node in the list, because then one has direct
access to it and "almost-direct" access to the first
node.
last 9 17 22 26 34
Constructors
list<T> l; Construct l as an empty list<T>
list<T> l(n); Construct l as a list<T> to contain n elements (set to
default value)
list<T> l(n, initVal); Construct l as a list<T> to contain n copies ofinitVal
Construct l as a list<T> to contain copies of elements in
list<T> l(fPtr, lPtr); memory locations fptr up to lptr (pointers of type T * )
Copy constructor
Destructor Destroy contents, erasing all items.
~list()
78
l1.merge(l2);
Remove all the elements in l2 and merge them into l1; that
is, move the elements of l2 into l1 and place them so that
the final list of elements is sorted using <; (Assumes both l2
and l1 were sorted using <)
l1.splice(pos, l2); Remove all the elements in l2 and insert them into l1 at
iterator position pos
l1.splice(to, l2, from); Remove the element in l2 at iterator position from and insert
it into l1 at iterator position to
l1.splice(pos, l2,
first, last); Remove all the elements in l2 at iterator positions
[first, last)and insert them into l1 at iterator position
l1.swap(l2); pos
Swap the contents of l1 with l2
l1 = l2 Assign to l1 a copy of l2
l1 == l2 Return true if and only if l1 contains the same items as l2,
n the same order
l1 < l2 Return true if and only if l1 is lexicographically less than l2
79