Compilers and lab instructions can be found here
You can post to the bulletin board; either questions
or answers, or something cool you think other students would like.
Pointers -- Chapter 3
Weiss Chapter 10 Lafore
Why does C++ use pointers
Pointers are used a lot in accessing array elements in
older C++ or C code
They are also used to pass arguments to a function
where the argument needs to be changed
They are used to access dynamic variables or objects
(stored on the heap)
Used in data structures like linked lists and trees
Some simple concepts
Every byte in a computers memory has an address
When a program is loaded into memory, it occupies a
certain range of addresses on the runtime stack
Every variable or functions starts at a certain
address
This address is
stored in a symbol table with the variable or function name so you can use the variable
name to directly access the value stored there
But it is also possible to have addresses stored as
the value of variables;
in this case you can indirectly access the value
of the variable whose address is stored there
Using addresses in C++
There are two new operators that are used with addresses
in C++
The
&, address-of operator
The *, which is used in two ways with
pointers
It
is used to declare pointer variables
It is also used to dereference pointer variables;
To dereference means to return the value at the
address in the pointer variable
The address-of operator
You can find the
address of a variable by using the address-of operator &
Run this program:
varadd.cpp
#include <iostream>
using namespace std;
int main()
{
int var1 =
11, var2 = 22;
int var3 =
33;
cout
<< &var1 << endl
<< &var2 << endl
<< &var3 << endl;
return 0;
}
Pointer Variables
Pointer variables
contain memory addresses as their values.
Declaring pointer variables
This is the first use of the *
operator
A pointer is declared to contain the address of a certain
data type
int* valPtr,
val1;
int*
xPtr * yPtr;
float* zPtr;
A pointer can only contain the address of that particular
data type
Pointers should be initialized to 0 or null
xPtr = 0; // initialize to null
xPtr = NULL
The danger of uninitialized
pointers
Even if you do not give a pointer a value, it is still
pointing at something.
Most of the time this will cause your program to
crash, because the address it points to will not make sense in your program
But sometimes it may not cause a crash
This will make
your program do strange things, but may not crash until later, or at all
If you are changing something that the pointer points
to, it may not show up until later in your program
This is a very
hard runtime error to find, since the source of the error, and where it shows
up may be far apart.
Accessing the variable pointed to
The pointer is dereferenced to access the
variable it points to
The dereference operator is the *
An example
int
main()
{
int var1,
var2;
int* ptr;
ptr =
&var1;
*ptr = 37;
var2 = *ptr;
cout
<< var2 << endl;
return 0;
}
// notice that all these are stored on the
runtime stack;
i.e. statically
Summary so far
& Returns the address of
its operand
* Is
used to declare a pointer
* Returns
the contents of the address it stores
Called the dereferencing operator
int y = 5;
int *yPtr;
yPtr = &y;
Examples of pointer use
cout<< *yPtr <<endl;
*yPtr = 9;
cin >> *yPtr;
Using pointers
Assume we these
declarations:
int y = 5, x = 8;
int *ptr;
ptr = &y;
What is the result of each of these statements?
ptr = x; //error
*ptr = x;
ptr = &x;
*ptr +=6;
cout << x
<< y;
cout << *ptr;
Drawing diagrams
You will find you will make fewer errors with pointers
if you draw diagrams to show exactly what is happening.
Draw
diagrams for the following: (this was
the quiz we did in class)
int x = 12, y = 7;
int
*pt1, *pt2 ;
pt1 = &x; pt2 = &y;
*pt1+=3;
pt2 = pt1;
*ptr2 = 28;
cout << *pt1<< *pt2;
cout << x << y;
pt2=&y;
*pt2=*pt1;
*pt2 +=2;
cout << *pt1<< *pt2;
The stack and heap
Terminology
Static RAM is
often called the runtime stack
The program itself, functions, and named variables are stored on the
runtime stack
Dynamic RAM is
called the memory heap
This is memory available from the OS to be allocated to
programs as they execute
One of the main uses of pointers is to access data
allocated on the heap.
Memory management
Like Java,
objects can be created on the heap by calling new
The result of new is a pointer
to the newly created object on the heap
The only way to access data on the heap is with
pointers, since the only handle you have is the address where it is located
Example
int main( )
{
string *strPtr;
strPtr =
new string( "hello" );
cout
<< "The string is: " << *strPtr
<< endl;
cout
<< "Its length is: " << (*strPtr).length(
)
<< endl; // note the parententheses; the dot operator has higher precedence
than the * operator
*strPtr
+= " world";
cout
<< "Now the string is " << *strPtr
<< endl;
delete strPtr;
return 0;
}
Garbage collection
In Java, all space allocated on the heap is automatically
returned to the OS when it is no longer needed:
this is garbage collection
C++ has no garbage collection; it is up to the
programmer to return unused space on the heap to the OS so it can be used again
Memory leaks occur if this is not done.
The delete operator
When an object that has been allocated by new is no longer referenced, the programmer must return
the space to the OS.
This is done using the delete operator
Otherwise the memory it used is lost until the program
terminates.
The delete
operator is applied to the object through a pointer
delete strPtr;
the pointer itself still exists, but the memory it is
pointing to can now be reused by the operating system
Stale pointers
A stale pointer points to address space on the heap
that has been returned to the operating system by delete.
Sometimes this space will have been reused by the OS,
and sometimes it may not have.
Since this varies, it is a very hard bug to find.
The way this usually happens is by having more than
one pointer to an object (common in C++)
Using pointers for linked lists
Keeping list is one thing computers do all the time
There are several ways to store lists on the computer
In a text file
In arrays or vectors
In linked lists
In binary search trees (always keep the list sorted)
Using arrays to store lists
There are advantages and disadvantages to storing
lists this way
Advantages
Arrays are random access; if you know the index, you
can go directly to an item in the array
It is fast to add items to the end of the list
Disadvantages
If you wan to add an item to the front of the list, or
the middle, all the items behind must be shifted
Arrays must be stored contiguously in RAM, so the size
must be known when the array is put into RAM.
Even a vector must be reallocated when it gets too big
Using linked lists to store lists
The space for a linked list is allocated dynamically,
as a program runs
The head of the list is a pointer, which is stored on
the runtime stack.
Each item in the list is kept in a node, which is a
two part object
One part is of the type to be kept in the list
The other part is a pointer, which points to the next
item in the list.
Advantages and
disadvantages of linked lists
They allow you to insert items anywhere in the list by just
changing pointers
No data moving
They are stored non contiguously, so they can grow to
any size
They do not allow random access,
the list must be traversed to find an item.