C++ Pointer and Reference

name, pointer, reference

A variable occupies a memory storage.  It has an address and has content.

int i=5;

i has a memory location.  The address is &i.  The content (value) is 5.

A pointer is an address.  As above, &i is a pointer which points to i  (hence the name pointer).

One can create a pointer "variable" just like creating a regular variable.  For example, int * pt2i;  creates a pointer variable pt2i which is an integer pointer type int *.  Again, just like variable can be initialized, we initialize pt2i = &i;

Note that instruction pt2i = i;  will not compile.  Why?  because it is a type mismatch.  pt2i is an integer pointer type, whereas i is an integer type.  integer pointer type is different from integer type.  Compiler will catch that.

So, what is reference?

Many textbook will elaborate reference as alias and needs to be initialized, etc.  If you want learn more on that, check out the wikipedia.

I am not going there.  Instead, I will emphasis on how reference is used in function calls, namely call by value, call by pointer, and call by reference.

why three different things?

I can think of two reasons.  The most common reason is for functions.  Let's say we want to compute the cube of a number (as shown in the example below) with a function.  What are the different ways of doing it?

function produces results in return code

The purpose of making function calls is to get something back.  If we only want one thing back from the function, the result can be specified in the return type, such as int cubeV (i)  below.  

int cubeV(int xv) {

    return xv*xv*xv;

}

It is clean, but it can only return one object.  If we need more than one things, then we need to have those things returned in the "parameters", because we can have many things in the parameters.  So, in the cube example, how can we do it with parameter?

function produces results in parameter (by pointer)

In order for function to produce result(s) in parameter(s), the calling program needs to have a space in the parameters to store the result.  If we want the cube function to compute the cube and produce result in the original variable we passed to the function, we can specify the address of the variable as the calling parameter such as cubeP(&i).    The definition of cubeP function takes a pointer parameter int * so that  cubeP can read and write data to the location directly.  For example,

void cubeP(int *xp) {

    (*xp) = (*xp)*(*xp)*(*xp);

}

Note that we take address xp and read its content (*xp), self multiply 3 times and then write it back to xp address location.  By the same token, we can easily have two or more addresses in the function parameters.

Note also the return code for cubeP is void.  It means there is no return code from cubeP.  If needed, we could have other meaningful return from cubeP too.

function produces results in parameter (by reference)

Another way of passing "changeable parameters" to function is using reference.  What we really pass in is the variable itself as cubeR(i).  But, the function deals with it as "reference" such that it is ok to change the variable value directly.  For example,

void cubeR(int &xr) {

    xr = xr*xr*xr;

}

When we call it, say cubeR(i), we use i directly.  The function reads from i, and write to i.  This form is almost identical to cubeV() example above.  Note that the function behaves very differently if we just specify the parameter as int, such as:

void cubeR(int xr) {

    xr = xr*xr*xr;

}

Try it yourself.

What did you find?  Did you accomplish the cube function?  If not, why not?

 

examples (cube) of all three type of function calls

int cubeV (int);        // call by value, pass in an integer, but that integer can not be changed.

void cubeP (int *);    // call by pointer, pass in a pointer, function can change the value using the pointer. 

void cubeR (int &);       // call by reference, pass in a reference (theoretically).  In practice, people usually pass in an integer and the  function can change the value directly (as in the cubeR (i); example).

tmp = cubeV (i);  // call by value

    cubeR (i);       // call by reference

    cubeP (pt2i);

    cubeP (&i);    // call by pointer

    cubeR (iref);

Why cubeV return int, but the others return void?

Did you notice that cubeV (i); and cubeR (i); have same parameter, but produce different result?

In fact, as far as I know, cubeR (iref); is rarely used.  It is cumbersome to declare a reference and initialize it.  People just use the variable directly cubeR (i) and declare it as a reference so the called routine can change the value.

In other words, the calling routine use the same calling method cubeV(i) or cubeR(i).  cubeV does not change the value of i.  cubeR can change i.  The behavior is conditioned by how function parameter types are defined:  cubeV (int) versus cubeR (int &).  cubeV takes the input as a value.  cubeR takes the input as a reference.

pointer math

pointer++, +3  // check out the other page

no bound checking

string pointers

array of string pointers

#include <iostream>

#include <iomanip>

using namespace std;

int cubeV (int);

void cubeP (int *);

void cubeR (int &);

void main() {

    int    i = 5;

    int     tmp;

    int * pt2i = &i;

    //////// function calls

    tmp = cubeV (i);  // call by value

    cubeR (i); // pass in i, i was interpreted as a reference, so the value of the i can be changed

    cubeP (&i);   // pass in address of i (the pointer to i)

    cubeP (pt2i); 

    int *ip = new int(3);

    cubeP (ip);

    ip = &tmp;

    // pointer math

    int a[3]={11,22,33};

    pt2i = & a[0];

    pt2i++;

    i = *pt2i;

    int x=44,y=55;

    pt2i = &y;

    pt2i = &x;

    pt2i -= 3;

    i = *pt2i;

}

// call by value, input parameter is not changed.  result is in the return

int cubeV(int xv) {

    return xv*xv*xv;

}

// call by pointer, content of xp is used and changed by the function.  content of xp is typically denoted by *xp

// note that we do not need return value because *xp is directly changed by the function.

void cubeP(int *xp) {

    (*xp) = (*xp)*(*xp)*(*xp);

}

// call by reference, xr is changed directly

void cubeR(int &xr) {

    xr = xr*xr*xr;

}