Pointers- an Intro

The following topics are covered in this section:

Address of a variable (An introduction to pointers)

Before we get into pointers let’s take a real-life analogy. A city consists of a lot of houses. To locate a house you need to have an address (and that address should be unique otherwise we would have lots of confusion). Similarly, computers deal with memories instead of cities. They store data in memory at particular locations. Memory consists of lots of bits. Each memory location can store a byte (8 bits make a byte and it is more logical to consider them as bytes rather than as individual bits). A memory location is like a house, which has a variable (instead of people) residing in it. Actually it is the value of the variable that resides in the house. You may remember that a character requires one byte for storage, an integer two/four bytes etc. Computers use memory addresses to access the memory locations.

Pointers are variables that store memory address. This address is usually the address of another variable. All variables are stored in memory locations.

Just like a house has a unique address, every memory location will have its own address. In computers the address is a hexa decimal number. For example: 0X8566fff4 is a hexadecimal number representing an address. Hence when we say that values of variables are stored in the computer, we actually mean that the value has been stored in a particular address.

When we write:

int x=5;

we might be thinking that ‘x’ is physically having a value of 5. In reality, ‘x’ will correspond to some memory location and it is in this location that the value 5 is stored (5 is stored in a binary format and not as a decimal number). This is why a variable is sometimes defined as a named memory location. It is more convenient for us to work in this way (a programmer cannot be expected to know the addresses where variables are allocated memory).

So, how do we find out the address of a variable? The ‘address of’ operator is denoted by ‘&’. This can be applied to any variable as illustrated below:

#include <iostream.h>
int main ( )
{
int var=100;
cout<<"Value : "<<var;                     // The output will be 6
return 0;
}

The output would be:

Value : 100

Pointers

Pointers are variables that store memory address. This address is the address of another variable. Hence a pointer points to another variable.

Declaring a Pointer:

Syntax:

data-type *name-of-pointer;

When * is used in declaration statements, it denotes a pointer. The data type denotes the data type to which the pointer points.

Let's see an example:

int main( )
{

int marks = 70; // marks is an integer
int * p; // p is a pointer
p = &marks; // p points to marks
cout<<"\nValue at that address is : "<<*p; // display the value.
return 0;
}

The only doubt you may have is about

cout<<* p;

In this context * is known as a de-referencing or indirect value operator. This operator will give the value stored at a particular memory location (in other words it will give the value stored at a particular address). It is the complement of the ‘&’ operator. Hence, *p means value at p (which holds address of marks).

The output of the program is:

Value at that address is : 70

To summarize:

• we can say that * means 'value at the address'.
• Both the operators * and & can be considered as pointer operators.

The figure below should make the concept of the program very clear to you: Everything is stored in memory. So what about the pointer itself. A pointer stores an address; but where does it store it? The answer can be found in the above figure. The pointer itself has a memory address where it stores the address of the variable that it points to. Confusing? Basically, the pointer has an address where it stores another address. In the earlier program, if you type the following code:

cout<<&p;

You will get the result as 006AFDF0. That is the address of the pointer itself.

This brings to view another point. The difference between pointers and a general variable is that address is primary for pointers. The value stored at the address is secondary. For other variables, the value is primary while the address where the value is stored is secondary.

If you want to find the value of ‘marks’ you would just write:

cout<<marks;

But if you want to find the address of ‘marks’ you have to write:

cout<<&marks;

In the case of pointers,

cout<<p;

will give the an address (address of the variable it points to) and the statement

cout<<*p;

will give you the value of the variable.

Be careful with Pointers

This section deals with some of the mistakes that can be committed using pointers.

1.) Make sure that your pointer variable points to the correct type of data. If you declare a pointer of type integer then make sure that the address it holds contains an integer.

float y = 6.6;             // y is a float quantity
int * p;                     // p points to an integer type
p = &y;                     // Wrong - p is supposed to point to an integer but y is a float.

2.) Be careful while making multiple pointer declarations.

Suppose you want to declare two pointers: p1 and p2 that point to an integer data type. You might be tempted to write the declaration as:

int * p1, p2;

Seems right, doesn't it? This declaration is wrong. This will declare p1 as a pointer pointing to integer type. The compiler will consider p2 as an integer and not a pointer. Since * precedes p1, the compiler considers only p1 as a pointer. Hence be careful while declaring pointers.

3.) A pointer should store an address.

Consider an extract from a program given below:

int *p;                     // marks is a pointer that points to data type long.
*p = 82;                 //wrong

Note the point that we have not yet stored any memory address in marks.

When a pointer is created the compiler will allot memory to hold an address. It will not allocate memory to hold the data to which the address points. Perhaps it's a bit confusing.

The problem with our program is that we are supposed to store an address in p. After storing an address in p you can then store some value at that address. What we have done is that we haven't assigned any address to p. Without an address you can't store a value. Hence the value 82 cannot be placed anywhere. A pointer which is not initialized is called a ‘dangling pointer’.

4.) Pointers are not the same as integers. Pointers hold a memory address and hence they cannot be multiplied or divided. Pointer addition will be discussed later.

5.) Not advisable to assign a memory address on your own (unless you are really sure of what you are doing).

Consider the following:

int * p;                                     //Correct
p = 006AFDF4;                     //wrong

A pointer stores a memory address. So you may think that the second line is correct. We have assigned a hexadecimal number to p (which is a pointer). The problem is that the compiler doesn't know that 006AFDF4 is a memory address. You may get an error message saying ‘data type mismatch’. Instead you can write it as:

p = (int * ) 0x006AFDF4;                 // This is correct.

This is correct because we are forcibly telling the compiler that this is a memory address (you’ll learn about forcing in the section on ‘casting’).

6.) Some programmers prefer to initialize a pointer to NULL. NULL is a predefined constant with a value of 0. When initialized to null, the memory address stored in the pointer will be: 0x00000000. The code below will compile but it is an erroneous code:

int *p;
int a=5;
cout<<*p;                 // value displayed is 910569528

In this code, the pointer ‘p’ hasn’t been assigned the address of ‘a’. ‘p’ will have some random memory location and reading the value at this location produces a garbage value. Programmers thus prefer to use:

int *p=NULL;
int a=5;
cout<<*p;

This code will generate an error when it is run in your computer because ‘p’ is pointing to the location 0x00000000.

7.) Potential hazards of using uninitialized pointers:

There are instances when a programmer declares a pointer and forgets to initialize it. Later in the code the programmer uses this pointer and this can lead to serious errors. Since the pointer has some unknown address value, when we dereference such a pointer we cannot predict what will be the value. A bigger problem might arise if you attempt to change the value stored at that address. For ex:

int *p;
*p=5;

In this case, the value at an unknown location will get changed to 5. This particular memory location could actually be some other variable in your program. Thus indirectly you would have changed the value of another variable and it will become difficult to trace the problem.

You may be wondering why we need to tell the compiler as to what type of data a pointer is going to point to? A pointer just holds an address, so why do we need to specify the data type pointed to?

The problem will occur when you make use of the dereferencing operator to get the value stored at the address. If a pointer points to a character, then the compiler knows that when we dereference the pointer it should only read one byte. If the pointer points to a short int the compiler knows that it has to read 2 bytes and so on. If we didn’t specify what data type the pointer will point to, then the compiler has no idea as to how many bytes it should read when dereferenced. And if we never dereferenced a pointer then we’d never know what is stored at a particular memory address!

What’s the difference between:

int *ptr;

and

int* ptr;

It is a matter of choice. Some programmers prefer the first one while you may frequently encounter the second type of declaration. The advantage of using the first method is that you are less likely to commit the mistake of declaring a pointer and an integer in one statement. Ex: if you want to declare to pointer ptr1 and ptr2, it is less likely to type

int *ptr, ptr2;

Use whichever method you are comfortable with.

Go back to the Contents Page