Contents
General Introduction
Chapter 1: Introduction: Objective, Target Audience and Article Revisions
C++ is a programming language that includes features of both low-level and high-level programming languages. It allows direct access to memory address locations but also provides advanced object-oriented programming capabilities. It is also backward compatible with C. The flexibility that C++ provides comes with enormous complexity. My purpose in this article is to demystify the complexity that creeps into C++ from pointers. Personally, once I had understood pointers in-depth, learning the rest of what is necessary to be learnt in C++ was very easy.
The article is targeted at beginners and intermediate users of C++. However, it can be helpful to anyone who wants to test his knowledge of pointer syntax in C++. Especially, the chapters, "Chapter 11: Deciphering (Long) Pointer Declarations" and "Chapter 9: Dynamic Memory Allocation: Multi-Dimensional Pointers" would be very useful.
I have made two major changes since the previous version of the article. C++ syntax is now colour-coded through images and a couple of illustrations have been added to make examples easier to understand. The entire article uses more than a dozen examples to illustrate core concepts. It helps to practice these examples yourself as you read along. The source code is included with the download version. All examples have been tested with GNU C++ compiler v3.4.
Please send your suggestions on improving the article and making necessary corrections at varunhome@gmail.com. You can also find some more tips on my webpage. Follow the link labeled 'Technical Articles'.
Part 1: Introduction to Pointers in C++
Chapter 2: The & and * Operators
A pointer is a variable which stores the address of another variable. There are two important operators when working with pointers in C++: the address of (&
) operator and the value of (*
) operator. They have been overloaded in C++ so they may have different uses in different contexts.
How much storage space does a pointer consume? Use sizeof(ptr)
without the '*
' operator to determine the memory utilised on your system. Irrespective of datatype or whether the pointer points to a single variable or an array, as a general rule, pointers must use the same amount of memory space.
The &
operator gives us the address of a variable and *
gives us the value of a variable at a specified address. For example:
Chapter 3: Pointers: First Example
Here is a simple example of using pointers in C++:
A diagram illustrating the relationships between the different variables in the above example should help clarify the concepts:
Chapter 4: Arrays of Pointers
Just as we have arrays of variables, so also we have arrays of pointers. For example,
int *p[5];
declares an array of five pointers to integer variables. More details on pointer syntax are provided in "Chapter 11: Deciphering (Long) Pointer Declarations". Each pointer in turn stores the memory address of an integer on its own. Each pointer may even store the base address of an array of integers. Let us understand the use of arrays of pointers with an example.
Part 2: Dynamic Memory Allocation and Linkage with Arrays
Chapter 5: Dynamic Allocation of Memory: Single Dimensional Pointers
In the above example, we did not allocate memory for the data pointed to by the pointer ptr[2]
. This is because it points to the array ch3
for which memory has already been allocated. However, in some cases, we may want a pointer variable to point to an unnamed memory location. We achieve this through the use of new
and delete
operators. Here is a simple example followed by a more complex example:
One thing to remember is the use of dynamic memory allocation in classes. When we create a class in C++, the compiler automatically creates four member functions, even if we don't create them:
- The default (no argument) constructor.
classname& classname ()
- The copy constructor.
classname& classname (classname&)
- The assignment (
=
) operator.
classname& operator=(classname&)
- The destructor
~classname ()
When we make a copy of a class containing a pointer, the pointer gets copied but the data that the pointer points to does not get copied. Therefore, always remember to make a copy of the data using dynamic memory allocation and store it in the pointer of the class copy. When overloading the copy constructor, you should therefore preferably overload the assignment operator also.
Chapter 6: Linkages Between Arrays and Pointer Syntax in C++
Array and pointer syntax is generally inter-changeable in C++. The next example reinforces these linkages covered briefly in the previous example.
Chapter 7: Multi-Dimensional Pointers
Just as we can have multi(2, 3, 4, .....)-dimensional variables, we can have multi-dimensional pointers also. A simple example is shown below:
You will find the above syntax used often in passing parameters to functions and accepting return values. Let us understand this through an example:
The usage of the above code can be easily understood from the following diagram. You should try and develop a diagram of your own to understand the example in Chapter 9: Dynamic Memory Allocation: Multi-Dimensional Pointers.
Chapter 8: Using Pointers to Return Values from Functions
I assume that you are aware of these keywords which are used in the next example:
exit (int)
: end program.
break
: stop execution of loop.
continue
: stop loop execution at present value, resume from next value.
return
: used to stop function execution. Can also be used without parameters in functions returning void.
Chapter 9: Dynamic Memory Allocation: Multi-Dimensional Pointers
Here is another more complicated example of dynamic memory allocation. We will allocate space for a two dimensional array of size [3][4] and manipulate it with a pointer.
The above example when used with three dimensional pointers to create an array of size [2][3][4], looks as follows:
When dynamic memory allocation fails, an exception is thrown. You would normally want to catch the exception and halt program execution. However before exceptions were used in C++ (or if you use the nothrow version of new
), whenever dynamic allocation failed, the pointer stored a NULL
value. In that case the following check would be used:
int *ptr = new int;
if(!ptr)
{
Part 3: Function Pointers and Deciphering (Long) Pointer Declarations
Chapter 10: Beginning with Function Pointers
Just as we have pointers to the basic datatypes, we have pointers to classes and structures also. They are used in exactly the same way as pointers to the basic datatypes. That is why we will not discuss how to use them here. We will instead concentrate on the use of function pointers.
Function pointers are pointers to functions. They are used when we do not know at the time of compiling a program the function we will need to call. They are often used in GUI libraries to execute a specified function when a particular signal (input) is received. The rules defining function pointers are the same as with other pointers. However, the declaration looks very different.
Chapter 11: Deciphering (Long) Pointer Declarations
This chapter explains rules to follow for deciphering pointer declarations. These are particularly important for function pointers.
- Start with the name that will identify the pointer, which is known as the identifier.
- Move to the right until you encounter a right-parenthesis [symbol = ")" ] or reach the end. Do not stop if the
()
brackets are used to pass parameters to a function. Also do not stop on encountering brackets used with arrays: [ ]
.
- Now go left of the identifier to continue deciphering the declaration. Keep going left until you find a left-parenthesis [the symbol "(" ] or reach the end. Do not stop if the brackets are used to pass parameters to a function.
- The whole interpretation should be a nice long sentence.
Here are a few examples to make the process clear:
Chapter 12: Function Pointers and typedef
Let us see an example of function pointers.
Let us conclude with the same example implemented with a typedef
declaration.