HomeC&C++WainTutorialsSamplesTip & TrickTools


Pointers are often considered to be the hardest part to master when programming C and C++. This is a brief note on the matter in the hope that it will shed some light on the matter.
First lets consider a plain variable:
   double x = 12.34;
What do we know about x and what can we learn? Actually a lot:
  • x has the value 12.34
  • x fills some bytes in memory, 8 in some cases
  • x is of type double
  • x has an address, we can't predict that
We can print these properties:
   std::cout << "Value: " <<  x << std::endl;
   std::cout << "Size: " << sizeof(x) << std::endl;
   std::cout << "Type: " << typeid(x).name() << std::endl;
   std::cout << "Address: " << &x << std::endl;
Now lets consider a pointer to double:
   double *p = &x;
What do we lern from this?
  • p has a value, which is the address of x
  • What p point at has a value, we get this value by using *p, p points in this case at x, so what p points at is 12.34
  • p has a size, 4 in some cases
  • p has a type, double *
  • p has an address &p
To print these:
   std::cout << "Value: " <<  p << std::endl;
   std::cout << "Content: " <<  *p << std::endl;
   std::cout << "Size: " << sizeof(p) << std::endl;
   std::cout << "Type: " << typeid(p).name() << std::endl;
   std::cout << "Address: " << &p << std::endl;
Now lets consider a reference to double:
   double &r = x;
Again we know something:
  • r has a value, which is the the value of x
  • r has a size, which is the same as the size of x
  • r has a type, which is double, not reference to double
  • r has an address, which is the address of x
Again we can print these:
   std::cout << "Content: " <<  r << std::endl;
   std::cout << "Size: " << sizeof(r) << std::endl;
   std::cout << "Type: " << typeid(r).name() << std::endl;
   std::cout << "Address: " << &r << std::endl;
It has been said that a reference is a alias for what it refer to.

And now to arrays and pointers.
We start off with an array of 4 doubles:
   double a[4] = {1,2,3,5};
What we can learn from this:
  • a has 4 values: 1,2,3,5
  • a has an size, 4 times the size of an double
  • a has an type, array of 4 doubles
  • a has an address, a, or &a or &a[0], which all is the same thing.
To show this:
   std::cout << "Value: " <<  a[0] << std::endl;
   std::cout << "Size: " << sizeof(a) << std::endl;
   std::cout << "Type: " << typeid(a).name() << std::endl;
   std::cout << "Address: " << a << std::endl;
   std::cout << "Address: " << &a << std::endl;
   std::cout << "Address: " << &a[0] << std::endl;
We can now create a pointer to double and let it point at a:
  double *p = a
Notice that there is no difference between a pointer to one double and a pointer to an array of doubles.
And now we can access a[0] thru p[0] and a[1] thru p[1], etc:
   int i;
   for(i = 0; i < 4; i++)
      std::cout << p[i] << std::endl;
We can also modify p, and thus make p point at something different:
   p++;
Will increment p to make it point at the next double in the array. We can use this to print all the doubles:
   for(p = a; p < &a[4]; p++)
      std::cout << *p << std::endl;
*p is the same as p[0]. &a[4] is the address of the element in the array just after the end.
If we have an reference to double, we can make it refer to one of the doubles in the array:
   double &r = a[1];
r will now refer to a[1], but we can't use r get a[2], nor can ve increment r to make it point at a[2], if we try we will just increment a[1].

And now to pointers and references used with functions.
Consider:
#include <iostream>
void Func(double foo)
{
   foo = 123;
}
int main()
{
   double bar = 333;
   Func(bar);
   std::cout << bar << std::endl;
}
What will the program print in main? The answer is 333.
Why is that? Func sets the value to 123!
This is because C++ use "call by value", that is, functions receives a copy of the parameters you supply. In this example Func recevies a copy of bar, set the value of this copy to 123, but this does not change bar.
If Func is to modify bar, we have two options, either give Func a pointer or a reference to bar. First the reference method:
#include <iostream>
void Func(double &foo)
{
   foo = 123;
}
int main()
{
   double bar = 333;
   Func(bar);
   std::cout << bar << std::endl;
}
And the pointer version:
#include <iostream>
void Func(double *foo)
{
   *foo = 123;
}
int main()
{
   double bar = 333;
   Func(&bar);
   std::cout << bar << std::endl;
}
Both do the same thing, so which to use is most a question on personal preference, some think the reference metod is easier to read and use.
Notice that Func in both cases receives a copy of the pointer/referece, but thats ok, they both refer to bar.
Now if the parameter in itself is a pointer:
#include <iostream>
void Func(char *s)
{
   s = "123";
}
int main()
{
   char *p = 0;
   Func(p);
   if(p)
      std::cout << p << std::endl;
   else
      std::cout << "P is NULL" << std::endl;
}
As expected (?) it will print "P is NULL", because Func receives and modify a copy of the pointer, and this does not modify p.
To solve it we can use a pointer to p, that is a pointer to pointer:
#include <iostream>
void Func(char **s)
{
   *s = "123";
}
int main()
{
   char *p = 0;
   Func(&p);
   if(p)
      std::cout << p << std::endl;
   else
      std::cout << "P is NULL" << std::endl;
}
Or a reference to p, that is a reference to pointer:
#include <iostream>
void Func(char *&s)
{
   s = "123";
}
int main()
{
   char *p = 0;
   Func(p);
   if(p)
      std::cout << p << std::endl;
   else
      std::cout << "P is NULL" << std::endl;
}

And now to arrays as arguments to functions.
Consider:
void Func(int Array[10])
{
}
int main()
{
   int A[10];
   Func(A);
}
We have learned that functions allways use "pass by value" and that functions receives a copy of the arguments we supply. This would in this case mean that Func receives a copy of the array, right?
No. When we specify that an array is used as argument to a function, the function we in fact receive a pointer!
To prove it:
void Func(int Array[10])
{
   Array[0] = 123;
}
int main()
{
   int A[10];
   A[0] = 111;
   std::cout << "Before Func: " << A[0] << std::endl;
   Func(A);
   std::cout << "After Func: " << A[0] << std::endl;
}
Which, when run, will print:
Before Func: 111
After Func: 123
If Func received a copy of A, it would modify the copy and not A.
Another way to see this:
void Func(int Array[10])
{
   std::cout << "Func size: " << sizeof(Array) << std::endl;
   std::cout << "Func type: " << typeid(Array).name() << std::endl;
}
int main()
{
   int A[10];
   std::cout << "Main size: " << sizeof(A) << std::endl;
   std::cout << "Main type: " << typeid(A).name() << std::endl;
   Func(A);
}
Which might print:
Main size: 40
Main type: int[10]
Func size: 4
Func type: int *
One consequence of this is that Func has no way to know how big the array is.
Notice that nothing prevents the user to call Func this way:
int main()
{
   int A[22];
   Func(A);
}
So if Func needs to know the size of the array, you have to tell et explicit, and Func has to trust the caller:
void Func(int Array[10], size_t Size)
{
}
int main()
{
   int A[22];
   Func(A, 22);
}
Now, if we are to transfer a 2D array to a function?
As we just learned we can't transfer an array to an function, the compiler will turn it into an pointer, if we try, but there is no easy way to turn a 2D array into a pointer. But with a little trick we will manage.
The standard guarantees that a 2D array is stored as one big block of memory, so it is possible to use a normal pointer to address the complete 2D array, we just have to help the compiler.
Consider:
   int A[3][4];
   A[2][1] = 123;
   std::cout <<  A[2][1] << std::endl;
   int *p = (int *)A;
   p[2*4 + 1] = 111;
   std::cout << A[2][1] << std::endl;
Here we have a 2D array of int's, we set A[2][1] to 123, and prints it, and surely it is 123.
Then we create a int pointer and let it point at the array A. (int *) is a cast, as A is not a int pointer.
Then we set the element p[2*4 + 1] to 111, and print A[2][1], which is now 111.
So we used p to access A.
The formula to get index A[i][j] for A[I][J] is p[i*J + j].
So if Func is to work on our 2D array we must supply an int * and J:
void Func(int *Array, int J)
{
   Array[2*J + 1] = 333;
}
int main()
{
   int A[3][4];
   A[2][1] = 123;
   std::cout << A[2][1] << std::endl;
   Func((int *)A, 4);
   std::cout << A[2][1] << std::endl;
}
Which, as we expect, will print 123 and 333.
The good news is that Func will be able to work for any sized 2D int arrays.
So how do we return an array from a function?
We can't, it's impossible, there is no way to do that, full stop.
But what to do then? Well, for a start we can return a pointer, which might point at an array.
You could write code such as:
int *Func()
{
   int x[10];
   return x;
}
But don't do that! When the function returns, x will disapear, and the returned pointer will point at void space.
Some compilers will issue a warning if you try, if it does not, get a propper compiler.
An quick and dirty way to fix this is to make x static:
int *Func()
{
   static int x[10];
   return x;
}
But each time Func is called it will return a pointer to the same array, and if that might not be what the caller expect.
You could make Func allocate space for the array:
int *Func()
{
   int *x = new int [10];
   return x;
}
The caller will then have to remember to deallocate:
   int *p = Func();
   delete [] p; 
Which might or might no be an elegant solution.
You could also use a std::vector:
#include <vector>
std::vector<int> Func()
{
   std::vector<int> Vect(10);
   Vect[2] = 0;
   return Vect;
}
int main()
{
   std::vector<int >Pop = Func();
}
This probably the most elegant solution, a unique "array" is returned each time, and the caller does not have to delete the vector.