More Pointers - II

The following topics are covered in this section:

Arithmetic operation on Pointers

You can't perform multiplication and division on pointers but you can do addition and subtraction on pointers. Suppose that p1 is a pointer that points to an integer and the address is 100 (yes, addresses will usually be a larger hexadecimal number but assume 100 as a memory address for simplicity). Also assume that an integer occupies 4 bytes. Now if we say:

p1++ ;

what would the above expression do? The value of p1 (i.e. the address pointed to by p1) gets changed. The address becomes 104 not 101 because an integer occupies 4 bytes. If an integer occupied 2 bytes then the result would be address 102. Similarly if you do:

p1--;

the address of p1 will be 98.

Hence, when a pointer is incremented it points to the memory location of the next element of its data type.

Similarly you could say the following:

p1 = p1 + 10;

This makes p1 point to the tenth element of p1's data type beyond the current position. If p1 points to a character type then p1 + 10 would move the pointer 10 bytes. Suppose p1 were a integer then p1 would move 20 bytes (if int occupies 2 bytes).

Addition of two pointers is not allowed. It doesn’t make logical sense to add two pointers because you won’t know what the new address will be. You’ll get a compiler error if you attempt to perform such an operation. But subtraction of two pointers is allowed since this will give you the number of elements lying between the two addresses.

You can use pointers to find the size occupied by a data type (i.e. without using the sizeof operator) as shown below:

long int i;
long int *ptr;
ptr=&i;
cout<<endl<<(long(ptr+1)-long(ptr));

This would give an output of 4 (the size of a long integer). You may be wondering why we are specifying long in the cout statement. If you typed:

cout<<endl<<((ptr+1)-(ptr));

the compiler would not evaluate the value for ptr+1. Instead it would simply expand the expression as: (ptr+1-ptr) which would give an output of 1. In the expression:

cout<<endl<<(long(ptr+1)-long(ptr));

long( ) is called explicit casting. This will be discussed in detail later (we force the compiler to store the result of ptr+1 in long integer format and we do the same for ptr).

The statement

cout<<endl<<(long(ptr+1)-ptr);            //ERROR

would cause an error saying that a pointer can only be subtracted from another pointer (or you’d get the message: Illegal pointer subtraction).

Assignment Operator with pointers:

Whenever we make use of pointers in a program we should be careful about what we are dealing with (i.e. are we wanting to refer to the memory location or do we want to use the value stored at that memory location). Consider two pointers, p1 and p2 (both pointing to integer data types).

p1=p2;

*p1=*p2;

In the first case, both p1 and p2 will now point to the same memory location. But in the second case only the value stored at the location pointed by p1 will change (i.e. the address will not change).

Similarly,

if (p1 == p2) and

if (*p1 == *p2)

are completely different. In the first case we are checking whether both pointers contain the same address while in the second case we check whether the value contained at the memory location pointed by them is equal.

Pointers and Arrays

Arrays can be accessed using pointers instead of their index numbers. Consider the following program:

int main( )
{

int marks;
int* p;
p = &marks;             // Pointer points to the first element of array.
marks=58;
marks=61;
marks=70;
cout<<endl<<*p;             // Output is 58, because p has address of array
cout<<endl<<*(p+1);         // output is 61, explanation below.
return 0;
}

Output is:

58
61

‘endl’ is a manipulator and it is the same as "\n". It is used to go to a new line. When you say *(p + 1), the pointer adds one to itself (this means that the pointer increments itself by the number of bytes of its data type). Hence it will go to the next integer address which is marks. The output will thus be 61.

Pointers and arrays are very closely related. In the above program instead of:

p = &marks;

try writing:

p = marks;

You might at first feel that this would lead to an error but it won’t. This is a perfectly correct statement. When you refer to an array name without using the index number, it means that you are referring to the address of the array (or in other words the address of the first element of the array).

Remember: An array’s name without an index number is the same as the address of the first element of the array. (This is a common question in C++ tests).

You might wonder then what is the difference between a pointer and an array name (i.e. an array identifier)? Are both the same?

Well, a pointer of type integer (like ‘p’ that was declared above) can point to any integer variable. ‘p’ can point to any other variable (as long as the variable is an integer type). But the array is constant. Whenever you use the array name, it will only refer to the same array. This means that the array is similar to a constant (it remains the same) and in fact it is sometimes called a constant pointer. Thus in the previous example:

p = marks;

is correct because pointer ‘p’ can take different values but

marks = p;

is invalid because ‘marks’ is like a constant pointer (value cannot be changed).

We refer to an array value by indexing:

marks=70;

using pointer we can write it as:

*(p+2)=70;

but even indexing in pointers is allowed:

p=70;

is also a valid statement.

Remember:

*(p+2) is 70 but

*p + 2 will not be 70. Since * has a higher operator precedence than +, the result of *p + 2 will be 58 + 2 (assuming that *p has a value 58). When using pointers to access array elements ensure that you use the parentheses.

Similarly it is not that only the pointer should be called by using the * operator. Since an array is also like a pointer, the following:

marks = 61;

is the same as:

*(marks+1) = 61;

Beware: Don’t confuse the de-reference operator (*) with the same * that is used to declare a pointer. Though they both seem the same, they are totally different in function; one is to declare a pointer and the other is to access the value held at that particular address.

int j;
int* p = &j;
j = 5;
cout<<*p;

The above piece of coding is correct because we are initializing the pointer ‘p’ to the address of the variable j.

Try this:

int* p=5;

Absolutely wrong! Cannot assign a value to ‘p’. Consider a modification of the above program.

#include <iostream.h>
int main( )
{

int marks;
int* p;
p = &marks; // Pointer points to the third element of array.
marks=58;
marks=61;
marks=70;
p = p-1; //pointer decrements by one, goes to the previous integer address
cout<<endl<<*p; // p is having address of marks.
cout<<endl<<*(p-1); // p is further decremented by one. This points to marks.
return 0;
}

The output would be:

61
58

There shouldn’t be any problem with the above program. We have made use of pointer arithmetic in an array.

We had discussed earlier about passing arrays to functions earlier and you can use any one of the following methods:

void disp(int a[ ] )

or:

void disp(int a )

Now you should have understood as to how the above two methods really work. In effect we are actually passing the address of the array to the function. Thus you could also pass a pointer to a function (of course the pointer should have the address of the array). See the example below:

#include <iostream.h>
void clear(int *point, int size)
{for (int i=0;i<size;i++)
{
*(point+i)=0;
}
}
int main( )
{int *p;
int marks={50,60,70};
cout<<"The original marks are : "<<marks<<" "<<marks
<<" "<<marks;
p = marks;
clear(p,3);
cout<<endl<<"The cleared marks are : "<<marks<<" "<<marks
<<" "<<marks;
return 0;
}

The output will be:

The original marks are : 50 60 70
The cleared marks are : 0 0 0

‘p’ is a pointer to an integer having the address of marks array. Hence this pointer is passed to the function ‘clear’ which uses this pointer to clear the entire array (it sets all the values of the elements to 0).

clear(p,3);

you could even have used:

clear(marks,3);

This would have also worked perfectly well because ‘p’ and marks mean the same thing.

Another modification you could have done is to change the function syntax to:

void clear(int m[ ],int size)
{
for (int i=0;i<size;i++)
{
m[i]=0;
}
}

The relationship between pointers and arrays may seem confusing at first, but with practice you’ll soon master the topic.

Remember: When an array is passed to a function it is passed by reference (and not by-value). If the function makes any changes to the array then the original array will be affected because the address is passed and not the value (this is called ‘passing by reference’ and is discussed in the next section).

Go back to the Contents Page