C++ Pointers

C++ Taking the Bull by the Horns - Part 5

Chrys Forcha
Introduction
This is part 5 of my series, C++ Taking the Bull by the Horns. In this part of the series, we look at the meaning of the C++ derived object type called, pointer.

Recall
The memory of a computer is a series of cells. A consecutive group of these cells is a region or an object. An object can hold a datum. This datum is the value of the object. There are different types of data. In one of the previous parts of the series we talked about the int, float, char, _Bool and void object types. Those are the fundamental object types. A derived object type is a combination of two or more fundamental object types. There is a derived type called the pointer. The pointer is the focus of this part of the series. An object can hold a pointer.

The series of cells of the memory are numbered numerically, consecutively. These numbers are called addresses. So each memory cell has a unique memory address.

You will take things in this tutorial the way I give you. Do not try to make analogy with the human language (English). Do not also try to make analogy with mathematic statements. Just take things the way I give you in order not to be misled by human language or mathematics.

Note that I have been talking about object types and not data types. The phrase data type is having resemblance in human language and mathematics. Using the phrase, data types, can be misleading and make your understanding of C++ difficult. Remember, the philosophy in this series is to learn C++ as it is, after that you decide on what to do with it. That is, after learning it you decide on how you will use it to solve mathematical problems and other problems, expressed in human language.

If you are not new to programming in general, you might wonder why I teach pointers early in the series. Other authors teach pointers late in their books or tutorials because they are making analogy of C++ with human language and mathematics. It makes sense to teach a computer language by likening it to the human language and mathematics. I believe, this approach works well with other computer languages, but not with C++ or its small brother, C. As I said at the beginning, I present C++ to you the way the inventors see it, but in simple terms. The object type, pointer, is an important feature in C++, and you most learn it. It is used a lot to do many other things in C++. So I have to teach you pointers early enough in the tutorial. In that way, I believe, you will understand the rest of the series easily.

Note: If you cannot see the code or if you think anything is missing (broken link, image absent), just contact me at forchatrans@yahoo.com. That is, contact me for the slightest problem you have about what you are reading.

This is important: Do not add or subtract in your mind, any idea to what I give you in this part of the series and in the rest of the series. In order for you to do that you would have to liken what I give you to the human language or mathematics. I believe, doing that would be misleading and you would not find the study of C++ easy.

The Pointer
You can have an object called the Pointer object. This is just like any other object. Here is the point to note: the value (content) of a pointer object is a memory address. That is, if an object has a value that is a pointer, it means there is a memory address in the region of the object. This memory address is actually pointing to some other region (object) in memory. In other words, this memory address is the address of some other object. We have just talked about two objects: the pointer object and some other object. The value (content) of the pointer object is the memory address of some other object. Remember an object is a region in memory.

The value in the other object can occupy more than one consecutive memory cells. For the pointer object, the address it has is that of the first memory cell of the other object. We say the pointer object points to the other object, because it has the memory address (first cell) of the other object. The pointer is actually the memory address of the pointer object. The pointed object is the other object.

Of course the pointer object and the pointed object can have identifiers. We saw identifiers in the previous part of the series.

Note: When dealing with a pointer, know that two objects are concerned.

Reference operator
C has what is called the reference operator. It is the & symbol. If you have an identifier as we saw in the previous part of the series, when you precede it with the & symbol, the resulting expression returns an address to the object. Let us say you have the following declaration:

int hisInt;

then the following expression will return the memory address of the object identified by, hisInt:

&hisInt

In programming, you do not need to know the exact number for the address, so do not worry about the exact address number as we go along. The reference operator, used in the above way is also important in C++ programming.

The Dereference operator
C++ has many operators. One of them is called the dereference operator. It is the * symbol. It can be typed in front of the pointer object identifier. This operator actually has two meanings so far as pointers are concerned: When used in the declaration or initialization of a pointer object, it refers to the address of the pointed object. When used with the pointer object after creation (declaration or initialization) of the pointer object, it refers to the value of the pointed object. We shall see examples of these below.

Creating a Pointer
Consider the following code segment:

float hisFloat;
float *myPointer;

myPointer = &hisFloat;

As I said above, whenever you are talking about a pointer, two objects are concerned: the pointed object and the pointer object. The pointed object above has the identifier, hisFloat. It is of type float. In the previous part of the series, we saw declarations similar to the first line (pointed object) above. We have the declaration for hisFloat; you could assign a value to it if you wish.

Next in the code segment, you have the declaration of the pointer object. It begins with the type of object of the pointed object. It does not begin with any type indicator for the pointer object. Next, you have a space and then the dereference operator, *. Then you have the identifier that identifies the pointer object. Do not confuse between pointer object and pointed object.

There is no type indicator for the pointer object. * is not the type indicator for the pointer object. * has two meanings so far as pointers are concerned (see below).

The last statement above, obtains the address (&hisFloat) of the pointed object and assigns it to the pointer object, identified by the identifier, myPointer. Remember, when using an identifier after declaration (or initialization), you do not precede it with any object type indicator; that is what we have done in the last statement. Also note that for the case of pointers, the identifier of the pointer is not preceded by *.

Note the way the pointer object identifier is declared. It is not declared the way object identifiers of other types are declared. The identifier is preceded first with the object type of the object it is pointing to; then you have the space and the dereference operator; before the identifier.

You can create a pointer object by initialization. Consider the following code segment:

float hisFloat;
float *myPointer = &hisFloat;

This code segment is similar to the previous. The second and third statements of the previous code have been joined into one, in this code segment.

In the above two code segments, the identifier of the pointer object is myPointer. Now, this is important: In the above code segment, the dereference operator has been used to assign a memory address as value to the pointer (object). This is one use of the dereference operator. The other use is given below.

Dereference Operator as Value Of a Pointer
After creating the pointer, you can use the identifier of the pointer object with or without the dereference operator in front of it. Under this condition, when the dereference operator is in front of it, the identifier has one meaning; when it is absent, the identifier has a different meaning. So after creation, you can use the above pointer, like,

myPointer

or like

*myPointer

After creation of the pointer object, to use its identifier, you do not precede it with any object type indicator; you can precede it with the dereference operator or omit the dereference operator, as shown above.

When the dereference operator is absent, the identifier refers to the address of a pointed object; that is the address of the pointed object can be assigned to the identifier (object) or the identifier can return the address of a pointed object, when * is absent. When the dereference operator is present, the identifier refers to the value (content) of the pointed object; that is, the value for the pointed object can be assigned to the identifier, or the identifier can return the value of the pointed object, when * is present.

In the following example, the dereference operator has been used in front of the object identifier after creation. Read the code and note that a value of 23.5 has been assigned to the pointed object. Try the code.

#include
using namespace std;

int main()
{
float hisFloat;
float *myPointer = &hisFloat;

*myPointer = 23.5;

cout
return 0;
}

The output should be 23.5. In the second line of the block, the dereference operator refers to the address in the pointer object. In the third and fourth lines it is referring to the value (content) of the pointed object.

Some three points to note
There are three points to note: The first point is, when the dereference operator is used in the step of the declaration or initialization (during creation) of a pointer object identifier, the pointer identifier is referring to the address of the pointed object (which is in the pointer object). The second point is, after creation of the pointed object, the absence of the dereference operator in front of the identifier of the pointer object, means that the pointer identifier is still referring to the address of the pointed object (like in the first code segment, above - under creating a pointer). The third point is, when the dereference operator is used after creation of the pointed object, in front of the pointer identifier, the pointer identifier refers to the value of the pointed object.

Another way to put the above information is as follows: During initialization of the pointer, the dereference operator is used with the identifier of the pointer object in the left operand and the right operand is a memory address (e.g. *myPointer = &hisFloat;). During declaration of a pointer identifier, the dereference operator is used in front of the identifier for the pointer (e.g. float *myPointer;). After initialization or declaration of the pointer identifier, the dereference operator in front of the identifier of the pointer object means the value of the pointed object (e.g. *myPointer = 23.5;), while the absence of the dereference operator in front of the identifier of the pointer object means the address of the pointed object (e.g. myPointer = &hisFloat;).

You can get the address of an object from the identifier of a non-pointer object. A non-pointer object is one which is declared without the dereference operator (e.g. int hisInt;) or one which is initialized without the dereference operator (e.g. int hisInt = 86;). To get the address, you precede the identifier with, &.

No Pointer Object Type Indicator
The pointer object has a pointer object type (address) as value. However, there is no object type indicator for a pointer object. The object type indicator for an integer object is, int; that for a float object is, float; that for a Boolean object is _Bool; and that for a character object is, char. Despite this, there is no object type indicator for a pointer object. You just play around with the * symbol to have a pointer.

Creating Pointers without using the Reference Operator
Above, we created the pointer object either like,

float hisFloat;
float *myPointer;

myPointer = &hisFloat;

or like

float hisFloat;
float *myPointer = &hisFloat;

In either of these methods, we had to create the pointed object first (in the first line) and then create the pointer object next assigning the address of the pointed object to the pointer object. It is possible to create the pointer object without first creating the pointed object; in this case you would not use the reference operator (&). However, in this case you have to be careful with the method you use. The successful method here is to declare the pointer identifier, in one statement, then assign the value of the pointed object in another statement. The other method of initialization does not work. Read and try the following code, which shows the successful method:

#include
using namespace std;

int main()
{
int *myPointer;
*myPointer = 453;

cout
return 0;
}

The above code works. We have obtained the pointer object without first creating the pointed object and so we have obtained the pointer object without using the reference operator. In this situation, the operating system creates the pointed object for you. As the operating system creates the pointed object for you, you do not have any identifier for the pointed object.

The other method, you might want to use to create a pointer object without first creating the pointed object and without using the reference operator, is the method of initialization. This method does not work. The following statement does not work:

int *myPointer = 453; //does not work

Do not use this initialization method. In creating objects you generally can use the declaration method (and then assign later) or you can use the initialization method. In the case of creating a pointer object without first creating the pointed object and without using the reference operator, you should not use the initialization method. In this case the initialization method is illegal. The initialization method for pointers works only when you have first created the pointed object and the right operand is a memory address.

Even though the declaration and initialization processes have similarities, it is advisable to treat them as two different processes (especially with pointers).

Constant
In the previous part of the series, we were dealing with one object. This one object has an identifier. There we talked about making the value (content) of the one object constant (unchangeable). In this part of the series, we are talking about two objects: the pointer object and the pointed object. In this section, the focus is on the pointed object. So, here, we have two things we can make constant (unchangeable): the value of the pointed object or the pointer (address) to the pointed object. Remember, the pointer (address) to the pointed object is the value of the pointer object.

You make either the value or the pointer constant in the declaration or initialization step. The syntax to make the value of the pointed object constant is:

const Type *pointerIndentifier

An example is,

const int *myPointr

This is important: Under this condition, you cannot change the value of the pointed object using the pointer.

The syntax to make the pointer to the pointed object constant is,

Type *const pointerIdentifier

An example is,

int *const myPointr

Note the position of * and the word cont in the two constant cases. Read and try the following code where the value of the pointed object is made constant:

#include
using namespace std;

int main()
{
int hisInt = 55;
const int *myPointer = &hisInt;

cout
return 0;
}

The above code works. The following code is the above, modified, by trying to change the value of the pointed object using the pointer object. Read and try to compile the code, and note that the compiler will issue an error message.

#include
using namespace std;

int main()
{
int hisInt = 55;
const int *myPointer = &hisInt;

*myPointer = 70; //cannot be allowed

cout
return 0;
}

"*myPointer" outside of the declaration or initialization means the value of the object pointed to by myPointer. myPointer is the identifier of the object having the pointer (address) of the pointed object. The statement added, "*myPointer = 70;" tries to change the constant value of the pointed object; so the compiler does not compile the code and issues an error message.

Read and try the following code where the pointer to the pointed object is made constant:

#include
using namespace std;

int main()
{
int hisInt = 55;
int *const myPointer = &hisInt;

cout
return 0;
}

The above code works. The following code is the above, modified, by trying to change the pointer (address) of the pointed object using the pointer object. Read and try to compile the code, and note that the compiler will issue an error message.

#include
using namespace std;

int main()
{
int hisInt = 55;
int *const myPointer = &hisInt;

int herInt = 80;
myPointer = &herInt; //cannot be allowed

cout
return 0;
}

Two statements were added. The first added statement creates a new object, identified by herInt. The value, 80 is assigned to this object. The second added statement tries to change the constant pointer (constant value of the pointer object) to the address of the new object. The compiler does not compile and issues an error message.

Constant Value, Constant Pointed Value and Constant Pointer
In C++, when we talk of a constant value we are referring to the case of a single object whose value is constant as we saw in the previous part of the series. When we talk about constant pointed value, we are referring to the case of two objects (pointed and pointer), where the value of the pointed object is constant. When we talk about constant pointer, we are referring to the case of two objects (pointed and pointer), where the pointer (address of the pointed object in the pointer object) is constant.

Void Object Type
When an object has no value, and it has not been reserved for an int or float or any of the other object types, it is said to have a void object type.

Void Pointer Type
A pointer that points to an object that is a void object type, is said to be a pointer of void pointer type. Here we have two objects: the pointer object and the pointed object. The pointer object is normal, and it has a pointer (address) to some other object. This other object is empty and has not been reserved for an int or float or any of the other object types.

Null Pointer
When you talk about a pointer you talk about two objects: the pointer object and the pointed object. When declaring a pointer object you have to precede it with the object type of the pointed object; that is always the case. A situation may arise when you would have a pointer, for a particular type of object, but it has not been decided if that object is to exist. In other words you have just one object, the pointer object, which will hopefully point to an object of a particular type, but at the moment is not pointing to any object. In this case, the inventors decided that the value of the pointer object does not have to be empty, it has to be zero. Such a pointer does not point to any object. Such a pointer is called a null pointer. The following code illustrates this:

int * myPointer;
myPointer = 0;

The object identified by myPointer here is a null pointer. Its value is zero. It will hopefully point to an integer object, but at the moment it is not pointing to any object. When you want it to point to an integer object, just assign the object's address to it; something like,

myPointer = &hisInt;

You can have a null pointer that will hopefully point to a float object; in that case you start with float in the declaration or initialization (the above pointer starts with int). In a similar way, you can have a null pointer for any object type; just start with the object type in the declaration or initialization of the pointer.

Well, it has been a long ride for this tutorial. We have come to its end. One peculiar thing to remember is that you cannot initialize a pointer without the address of a pointed object on the right operand, even though the dereference operator on the left operand means, value of the pointed object.

If you have understood all what I have written in this tutorial, then you have achieved something; you need to relax. Go somewhere and have a drink, relax, before you come back and continue with the next part of the series. The study of Pointers is one of the greatest headaches in C++.

Chrys

To arrive at any of the parts of this series, just type the corresponding title below in the Search Box of this page and click Search (you can also use any available links):

C++ Taking the Bull by the Horns - Part 1
C++ Taking the Bull by the Horns - Part 2
C++ Taking the Bull by the Horns - Part 3
C++ Taking the Bull by the Horns - Part 4
C++ Taking the Bull by the Horns - Part 5
C++ Taking the Bull by the Horns - Part 6
C++ Taking the Bull by the Horns - Part 7
C++ Taking the Bull by the Horns - Part 8
C++ Taking the Bull by the Horns - Part 9
C++ Taking the Bull by the Horns - Part 10
C++ Taking the Bull by the Horns - Part 11
C++ Taking the Bull by the Horns - Part 12
C++ Taking the Bull by the Horns - Part 13
C++ Taking the Bull by the Horns - Part 14
C++ Taking the Bull by the Horns - Part 15
C++ Taking the Bull by the Horns - Part 16
C++ Taking the Bull by the Horns - Part 17
C++ Taking the Bull by the Horns - Part 18
C++ Taking the Bull by the Horns - Part 19
C++ Taking the Bull by the Horns - Part 20
C++ Taking the Bull by the Horns - Part 21
C++ Taking the Bull by the Horns - Part 22
C++ Taking the Bull by the Horns - Part 23
C++ Taking the Bull by the Horns - Part 24
C++ Taking the Bull by the Horns - Part 25

Published by Chrys Forcha

I have more than 10 years experience in computer programming, software, electronics and telecommunications. I have a First Degree in Electronics and a Master's Degree in Technical Education. As well a...  View profile

To comment, please sign in to your Yahoo! account, or sign up for a new account.