Session 5: Pointers and Arrays, Iterators

Introduction

Pointers and arrays

Pointers in C and C++

Undefined pointers

It is the programmer's responsibility to ensure that the pointer points at something whenever it is dereferenced.

Null pointers

More pointers

The following declaration
    const int *p;
Means that things pointed to by p cannot be changed through p (but p itself can be changed.)

It is possible to have pointers to pointers:

    int i;
    int *p1 = &i;
    int **p2 = &p1;
    int ***p3 = &p2;
and these may be qualified with const in various ways.

Pointers to objects

Given a class
    class Point {
    public:
        int x, y;
        Point (int xx, int yy) : x(xx), y(yy) {}
    };
We can refer to fields as follows:
    Point my_point(2, 3);
    Point *p = &my_point;
    cout << (*p).x << '\n';
or equivalently as
    cout << p->x << '\n';
and similarly for member functions.

Arrays

We have already used vectors, but C++ also has arrays, which are fixed in size:

        int arr[40];
        for (int i = 0; i < 40; i++)
                arr[i] = arr[i] + 5;
Unlike Java, there is no check that the index is in bounds.

Advice: use vectors instead unless the collection has a definite, fixed size.

Pointers and arrays

When assigning or initializing from an array, a pointer to the first element is copied, not the array:
    int arr[40];
    int *p = arr;
Now *p is equivalent to arr[0], and indeed to *arr.

The following are all equivalent:

    arr[0] = arr[0] + 5;
    *p = *p + 5;
    *arr = *arr + 5;

Parameter passing

Parameter passing is a form of initialization, so an array
    int arr[40];
can be passed as a pointer parameter:
    void f(int *p) { ... }
A function that really takes a pointer to a single element looks the same. (This is less common in C++ than in C, which has no references.)

C-style strings

Pointer arithmetic

Suppose p has type T *, and points to the ith element of an array of Ts. Then Again there are no checks that anything is in bounds.

It is also possible to subtract two pointers, which should be pointers to the same array.

Looping over an array

Given an array of integers:
    int arr[40];
The following are equivalent:

Iterators

An iterator is an object that provides sequential access to the elements of a container.

Iterators in the STL

Iterating over a list of strings:
    list<string> names;
    ...
    for (list<string>::iterator p = names.begin();
            p != names.end(); ++p)
        cout << *p << '\n';
Each sequence includes a type iterator for its iterators, and two iterators:
begin()
positioned at the start of the sequence, and
end()
positioned just past the end of the sequence.
Each iterator supports the operators ==, ++ and *.

A variation: typedefs

In C++ we can define new names for types using typedef:
    typedef int time;
    typedef char * cstr;
    typedef deque<string> phrase;
    typedef vector<vector<double> > matrix;
(We can also do this in C, but only outside functions.)

We can use a typedef to introduce an abbreviation for the iterator type:

    typedef list<string>::iterator iter;
    for (iter p = names.begin(); p != names.end(); ++p)
        cout << *p << '\n';

The analogy

C   STL  
array arr container c
pointer p iterator p
start pointer arr start iterator c.begin()
end pointer arr + LENGTH end iterator c.end()
increment ++p   ++p
dereference *p   *p

Iterator is a concept

Iterator concepts in the STL

Different containers have different kinds of iterator, belonging to a hierarchy of iterator concepts:
Input Iterator
supports ==, ++, (unary) * and ->

e.g. the iterator of slist (singly linked lists).

Bidirectional Iterator
supports all these as well as -

e.g. the iterator of list.

Random Access Iterator
supports all these as well as <, +, - and [], which should behave similarly to operations on pointers.

e.g. the iterator of vector or deque.

A generic function

template <typename Iterator, typename Elem>
int count(Iterator start,
          Iterator finish, const Elem & v) {
    int n = 0;
    for (Iterator p = start; p != finish; ++p)
        if (*p == v)
            n++;
    return n;
}
There several requirements here (checked at instantiation):

Using the generic count function

The count function is defined in <algorithm>.

Here is an example of its use:

    list<string> names;
    string s;
    ....
    int n = count(names.begin(), names.end(), s);
    cout << s << " occurs " << n << " times\n";
In the above use,

Iterating over associative containers

Printing out a map:
    map<string, int> table;
    ...
    typedef map<string, int>::iterator Iter;
    for (Iter p = table.begin(); p != table.end(); ++p)
        cout << p->first << " -> " << p->second << '\n';

Summary