Ghion Tech College Department of Computer Science
CHAPTER THREE
3. POINTERS
3.1. Introduction
Every data in the computer’s memory is stored in addressed places called bytes. The amount of
byte a data takes in the computer’s memory depends on its type i.e. whether the data is char, int,
float, double, etc .though it differs from machine to machine, char data type takes 1 byte memory;
int takes 2 bytes, etc.
Every byte in the computer’s memory has an address number. So, when your program is loaded
into memory, every variable in your program occupies portions of these addressed bytes starting
at a particular address and extends a certain range of bytes; based on the data type, it extends 1
address long for char data type, 2 addresses for int, etc note that this amount changes from
machine to machine.
We have already seen how variables are memory cells that we can access by an identifier. But
these variables are stored in concrete places of the computer memory. For our programs, the
computer memory is only a succession of 1 byte cells (the minimum size for a datum), each one
with a unique address. When you declare a variable, the computer associates the variable name
with a particular location in memory and stores a value there. When you refer to the variable by
name in your code, the computer must take two steps:
i. Look up the address that the variable name corresponds to
ii. Go to that location in memory and retrieve or set the value it contains
3.2. The nature of pointers
A pointer is a variable which stores the address of another variable. The only difference between
pointer variable and regular variable is the data they hold. Memory addresses, or pointers, allow
us to manipulate data much more flexibly; manipulating the memory addresses of data can be more
efficient than manipulating the data itself. Just a taste of what we’ll be able to do with pointers:
More flexible pass-by-reference
Manipulate complex data structures efficiently, even if their data is scattered in different
memory locations
There are two pointer operators in C++:
the address of operator ( & )
the dereference operator ( * )
1|Page Fundamentals of Programming-II
Ghion Tech College Department of Computer Science
Whenever you see the & used with pointers, think of the words “address of.” The & operator
always produces the memory address of whatever it precedes. The * operator, when used with
pointers, either declares a pointer or dereferences the pointer’s value. The dereference operator can
be literally translated to "value pointed by".
A pointer is simply the address of an object in memory. Generally, objects can be accessed in two
ways: directly by their symbolic name, or indirectly through a pointer. The act of getting to an
object via a pointer to it, is called dereferencing the pointer. Pointer variables are defined to point
to objects of a specific type so that when the pointer is dereferenced, a typed object is obtained.
At the moment in which we declare a variable this one must be stored in a concrete location in this
succession of cells (the memory). We generally do not decide where the variable is to be placed -
fortunately that is something automatically done by the compiler and the operating system on
runtime, but once the operating system has assigned an address there are some cases in which we
may be interested in knowing where the variable is stored.
This can be done by preceding the variable identifier by an ampersand sign (&), which literally
means, "address of”. For example:
ptr= &var;
This would assign to variable ptr the address of variable var , since when preceding the name of
the variable var with the ampersand ( & ) character we are no longer talking about the content of
the variable, but about its address in memory.
We are going to suppose that var has been placed in the memory address 1776 and that we write
the following:
var = 25;
x = var;
ptr = &var;
The result will be the one shown in the following diagram:
2|Page Fundamentals of Programming-II
Ghion Tech College Department of Computer Science
We have assigned to x the content of variable var as we have done in many other occasions in
previous sections, but to ptr we have assigned the address in memory where the operating system
stores the value of var , that we have imagined that it was 1776 (it can be any address). The reason
is that in the allocation of ptr we have preceded var with an ampersand ( & ) character.
The variable that stores the address of another variable (like ptr in the previous example) is what
we call a pointer.
3.3. Pointer declaration
It is reserving a memory location for a pointer variable in the heap. The general scheme for
declaring pointers is:
data_type *pointer_name; // Add "= initial_value " if applicable
Example: to declare a pointer variable called p_age, do the following:
int * p_age;
Whenever the dereference operator, *, appears in a variable declaration, the variable being declared
is always a pointer variable.
3.4. Assigning values to pointers
p_age is an integer pointer. The type of a pointer is very important. p_age can point only to integer
values, never to floating-point or other types.
To assign p_age the address of a variable, do the following:
int age = 26;
int * p_age;
p_age = &age;
Or
int age = 26;
int * p_age = & age;
Both ways are possible.
If you wanted to print the value of age, do the following:
cout<<age;//prints the value of age
Or by using pointers you can do it as follows
cout<<*p_age;//dereferences p_age;
3|Page Fundamentals of Programming-II
Ghion Tech College Department of Computer Science
The dereference operator produces a value that tells the pointer where to point. Without the *, (i.e
cout<<p_age), a cout statement would print an address (the address of age). With the *, the cout
prints the value at that address.
You can assign a different value to age with the following statement:
age = 13; //assigns a new value to variable age
*p_age = 13; //assigns 13 as a value to the memory p_age points at.
N.B: the * appears before a pointer variable in only two places: when you declare a pointer
variable and when you dereference a pointer variable (to find the data it points to).
The following program is one you should study closely. It shows more about pointers and the
pointer operators, & and *, than several pages of text could do.
#...
#...
int main( )
{
int num = 123; // a regular integer variable
int *p_num; //declares an integer pointer
cout<< “num is ”<<num<<endl;
cout<< “the address of num is ”<<&num<<endl;
p_num = #// puts address of num in p_num;
cout<< “*p_num is ”<<*p_num<<endl; //prints value of num
cout<< “p_num is ”<<p_num<<endl; //prints value of P_num
}
3.5. Pointer to void
Note that we can’t assign the address of a float type variable to an integer pointer variable and
similarly the address of an integer variable cannot be stored in a float or character pointer.
flaot y;
int x;
int *ip;
float *fp;
ip = &y; //illegal statement
fp = &x; //illegal statement
4|Page Fundamentals of Programming-II
Ghion Tech College Department of Computer Science
That means, if a variable type and pointer to type is same, then only we can assign the address of
variable to pointer variable. And if both are different type then we can’t assign the address of
variable to pointer variable but this is also possible in C++ by declaring pointer variable as a void
as follows:
void *p;
Let us see an example:
void *p;
int x;
float y;
p = &x; //valid assignment
p = &y; //valid assignment
The difficulty on void pointers is that, void pointers can’t be dereferenced. They are aimed
only to store address and the dereference operator is not allowed for void pointers.
3.6. Arrays of pointers
If you have to reserve many pointers for many different values, you might want to declare an array
of pointers.
The following reserves an array of 10 integer pointer variables:
int *iptr[10]; //reserves an array of 10 integer pointers
The above statement will create the following structure in RAM
.
.
.
.
.
.
.
.
.
.
iptr[4] = &age;// makes iptr[4] point to address of age.
3.7. Pointer and arrays
The concept of array goes very bound to the one of pointer. In fact, the identifier of an array is
equivalent to the address of its first element, like a pointer is equivalent to the address of the first
element that it points to, so in fact they are the same thing. For example, supposing these two
declarations:
5|Page Fundamentals of Programming-II
Ghion Tech College Department of Computer Science
int numbers [20];
int * p;
The following allocation would be valid:
p = numbers;
At this point p and numbers are equivalent and they have the same properties, with the only
difference that we could assign another value to the pointer p whereas numbers will always point
to the first of the 20 integer numbers of type int with which it was defined. So, unlike p, that is an
ordinary variable pointer, numbers is a constant pointer (indeed that is an Array: a constant
pointer). Therefore, although the previous expression was valid, the following allocation is not:
numbers = p;
Because numbers is an array (constant pointer), and no values can be assigned to constant
identifiers.
N.B: An array name is just a pointer, nothing more. The array name always points to the first
element stored in the array. There for , we can have the following valid C++ code:
int ara[5] = {10,20,30,40,50};
cout<< *(ara + 2); //prints ara[2];
The expression *(ara+2) is not vague at all if you remember that an array name is just a pointer
that always points to the array’s first element. *(ara+2) takes the address stored in ara, adds 2 to
the address, and dereferences that location.
Consider the following character array:
char name[ ] = “C++ Programming”;
What output do the following cout statements produce?
cout<<name[0]; // ____C__
cout<<*name; // _____C__
cout<<*(name+3); //_________
cout<<*(name+0); //____C____
3.8. Pointer Advantage
It allows management of structures which are allocated memory dynamically. It allows passing
arrays and strings to functions more efficiently. It makes possible to pass address of structure
instead of entire structure to function.
6|Page Fundamentals of Programming-II
Ghion Tech College Department of Computer Science
You can’t change the value of an array, because you can’t change constants. This explains why
you can’t assign an array a new value during a program’s execution: eg: if Cname is array of
characters then:
char Cname[20];
Cname = “Football”; //invalid array assignment;
Cname[ ]=”football”;//invalid array assignment;
Or
int array[6];
array = {1,2,3,4,5};//invalid array assignment
array[ ] = {1,2,3,4,5};//invalid array assignment
array = 1;//invalid
Unlike arrays, you can change a pointer variable. By changing pointers, you can make them point
to different values in memory. Have a look at the following code:
#include<iostream.h>
#...
int main()
{
float v1 = 679.54;
float v2 = 900.18;
float * p_v;
p_v = &v1;
cout<< “\nthe first value is ”<<*p_v;
p_v = &v2;
cout<< “\nthe second value is ”<<*p_v;
}
You can use pointer notation and reference pointers as arrays with array notation. Study the
following program carefully. It shows the inner workings of arrays and pointer notation.
int main ( )
{
int ctr;
int iara[5] = {10,20,30,40,50};
int *iptr;
iptr = iara; //makes iprt point to array’s first element. Or iprt = &iara[0]
cout<< “using array subscripts:\n”;
cout<< “iara\tiptr\n”;
for(ctr=0;ctr<5;ctr++)
{
cout<<iara[ctr]<< “\t”<<iptr[ctr]<< “\n”;
}
cout<< “\nUsing pointer notation\n”;
for(ctr=0;ctr<5;ctr++)
cout<< *(iara+ctr) << “\t” << *(iptr+ctr)<< “\n”;
}
7|Page Fundamentals of Programming-II
Ghion Tech College Department of Computer Science
Suppose that you want to store a person’s name and print it. Rather than using arrays, you can use
a character pointer. The following program does just that.
int main( )
{
char *c = “Meseret Belete”;
cout<< “your name is : ”<<c;
}
Suppose that you must change a string pointed to by a character pointer, if the person’s name in
the above code is changed to MeseterAlemu: look at the following code:
int main( )
{
char *c = “Meseret Belete”;
cout<< “your name is : ”<<c;
c = “Meseret Alemu”;
cout<< “\nnew person name is : ”<<c;
}
If c were a character array, you could never assign it directly because an array name can’t be
changed.
3.9. Pointer Arithmetic
To conduct arithmetical operations on pointers is a little different than to conduct them on other
integer data types. To begin, only addition and subtraction operations are allowed to be conducted,
the others make no sense in the world of pointers. But both addition and subtraction have a different
behavior with pointers according to the size of the data type to which they point to.
When we saw the different data types that exist, we saw that some occupy more or less space than
others in the memory. For example, in the case of integer numbers, char occupies 1 byte, short
occupies 2 bytes and long occupies 4.
Let's suppose that we have 3 pointers:
char *mychar;
short *myshort;
long *mylong;
And that we know that they point to memory locations 1000 ,2000 and 3000 respectively. So if we write:
mychar++;
myshort++;
mylong++;
mychar , as you may expect, would contain the value 1001 . Nevertheless, myshort would contain
the value 2002 , and mylong would contain 3004 . The reason is that when adding 1 to a pointer
we are making it to point to the following element of the same type with which it has been defined,
and therefore the size in bytes of the type pointed is added to the pointer.
8|Page Fundamentals of Programming-II
Ghion Tech College Department of Computer Science
This is applicable both when adding and subtracting any number to a pointer. It is important to
warn you that both increase ( ++ ) and decrease ( -- ) operators have a greater priority than the
reference operator asterisk ( * ), therefore the following expressions may lead to confusion:
*p++;
*p++ = *q++;
The first one is equivalent to *(p++) and what it does is to increase p (the address where it points
to – not the value that contains).
The second, because both increase operators (++) are after the expressions to be evaluated and not
before, first the value of *q is assigned to *p and then they are both q and p increased by one. It is
equivalent to:
*p = *q;
p++;
q++;
Now let us have a look at a code that shows increments through an integer array:
int main( )
{
int iara[ ] = {10,20,30,40,50};
int * ip = iara;
cout<<*ip<<endl;
ip++;
cout<<*ip<<endl;
ip++;
cout<<*ip<<endl;
ip++;
cout<<*ip<<endl;
}
3.10. Pointer and String
If you declare a character table with 5 rows and 20 columns, each row would contain the same
number of characters. You can define the table with the following statement.
char names[5][20] ={{“George”},{“Mesfin”},{“John”},{“Kim”},{“Barbara”}};
9|Page Fundamentals of Programming-II
Ghion Tech College Department of Computer Science
The above statement will create the following table in memory:
G e o r g e \0
M e s f i n \0
J o h n \0
K i m \0
B a r b a r a \0
Notice that much of the table is waster space. Each row takes 20 characters, even though the data
in each row takes far fewer characters. To fix the memory-wasting problem of fully justified tables,
you should declare a single-dimensional array of character pointers. Each pointer points to a string
in memory and the strings do not have to be the same length.
Here is the definition for such an array:
char *name [5] = {“George”,“Mesfin”,“John”, “Kim”,“Barbara”};
This array is a single-dimension array. The asterisk before names makes this array as an array of
pointers. Each string takes only as much memory as is needed by the string and its terminating
zero. At this time, we will have this structure in memory:
To print the first string, we should use:
cout<<*names; //prints George.
To print the second use:
cout<< *(names+1); //prints Mesfin
Whenever you dereference any pointer element with the * dereferencing operator, you access one
of the strings in the array.
3.11. Pointer to pointer
As the memory address of integer, float or character is stored into a pointer variable, the address
of a pointer can also be stored in another pointer. This pointer is said to be pointer to a pointer. An
array of pointer is conceptually same as pointer to pointer type. The pointer to pointer type is
declared as follows:
Data_type ** pointer_name;
Note that the asterisk is double here.
int **p; //p is a pointer which holds the address of another pointer.
E.g.:
char a;
char * b;
char ** c;
a = 'z';
b = &a;
c = &b;
10 | P a g e Fundamentals of Programming-II
Ghion Tech College Department of Computer Science
This, supposing the randomly chosen memory locations of 7230 , 8092 and 10502 , could be
described thus:
(Inside the cells there is the content of the variable; under the cells its location)
Have a look at the following code:
int main( )
{
int data;
int *p1;
int **p2;
data = 15;
cout<< “data = ”<<data<<endl;
p1 = &data;
p2 = &p1;
cout<< “data through p1 = ”<<*p1<<endl;
cout<< “data through p2 = ”<< **p2<<endl;
}
3.12. Dynamic memory
Until now, in our programs, we have only had as much memory as we have requested in
declarations of variables, arrays and other objects that we included, having the size of all of them
to be fixed before the execution of the program. But, what if we need a variable amount of memory
that can only be determined during the program execution (runtime)? For example, in case that we
need a user input to determine the necessary amount of space. The answer is dynamic memory, for
which C++ integrates the operators new and delete.
Pointers are useful for creating dynamic objects during program execution. Unlike normal (global
and local) objects which are allocated storage on the runtime stack, a dynamic object is allocated
memory from a different storage area called the heap. Dynamic objects do not obey the normal
scope rules. Their scope is explicitly controlled by the programmer.
a) The New Operator
In C++ new operator can create space dynamically i.e at run time, and similarly delete operator is
also available which releases the memory taken by a variable and return memory to the operating
system. When the space is created for a variable at compile time this approach is called static. If
space is created at run time for a variable, this approach is called dynamic. See the following two
lines:
11 | P a g e Fundamentals of Programming-II
Ghion Tech College Department of Computer Science
int a[10];//creation of static array
int *a;
a = new int[10];//creation of dynamic array
Let’s have another example:
int * ptr3;
ptr3 = new int [5];
In this case, the operating system has assigned space for 5 elements of type int in the heap and it
has returned a pointer to its beginning that has been assigned to ptr3 . Therefore, now, ptr3 points
to a valid block of memory with space for 5 int elements.
You could ask what is the difference between declaring a normal array and assigning memory to
a pointer as we have just done. The most important one is that the size of an array must be a
constant value, which limits its size to what we decide at the moment of designing the program
before its execution, whereas the dynamic memory allocation allows assigning memory during the
execution of the program using any variable, constant or combination of both as size.
The dynamic memory is generally managed by the operating system, and in the multi-task
interfaces can be shared between several applications, so there is a possibility that the memory
exhausts. If this happens and the operating system cannot assign the memory that we request with
the operator new, a null pointer will be returned. For that reason it is recommendable to always
verify if after a call to instruction new the returned pointer is null:
int * ptr3;
ptr3 = new int [5];
if (ptr3 == NULL) {
// error assigning memory. Take measures.
};
if ptr3 is NULL, it means that there is no enough memory location in the heap to be given for ptr3.
b) Operator delete
Since the necessity of dynamic memory is usually limited to concrete moments within a program,
once this one is no longer needed it shall be freed so that it become available for future requests of
dynamic memory. For this exists the operator delete, whose form is:
delete pointer ;
or
delete [ ] pointer ;
12 | P a g e Fundamentals of Programming-II
Ghion Tech College Department of Computer Science
The first expression should be used to delete memory allocated for a single element, and the second
one for memory allocated for multiple elements (arrays).
In most compilers both expressions are equivalent and can be used without distinction, although
indeed they are two different operators and so must be considered for operator overloading.
In the following simple example, a program that memorizes numbers, does not have a limited
amount of numbers that can be introduced, thanks to the concept and power of pointer that we
request to the system as much space as it is necessary to store all the numbers that the user wishes
to introduce.
#include <iostream.h>
int main ( )
{
char input [100];
int i, n;
long * num;// total = 0;
cout<< "How many numbers do you want to type in? ";
cin.getline (input,100);
i = atoi (input);
num = new long[i];
if (num = = NULL)
{
cout<<"\n no enough memory!";
exit (1);
}
for (n = 0; n<i; n++)
{
cout<< "Enter number: ";
cin.getline (input,100);
num[n] = atol(input);
}
cout<< "You have entered: ";
for (n=0; n<i; n++)
cout<<num[n] << ", ";
delete[] num;
return 0;
}
NULL is a constant value defined in C++ libraries specially designed to indicate null pointers. In
case that this constant is not defined you can do it yourself by defining it to 0:
13 | P a g e Fundamentals of Programming-II