Sei sulla pagina 1di 30

Pointers are one of the most important features of C++ language. Pointers need very careful handling.

There are many reasons for using pointers. A pointer allows a function or a program to access a variable outside the preview of function or program. Use of pointer increases makes the program execution faster. Using pointers, arrays and structures can be handled in more efficient way. To communicate with operating system about memory.

UNDERSTANDING POINTERS
Each memory location is assigned a unique number called location number or address.

Figure: Memory Organisation

A memory cell is either of one byte or more contagious bytes. Each cell can store one value at a given time. The address of a cell is always the address of first byte.

Figure: Representation of a variable in Memory

Since pointer is a variable, its value is also stored in memory in another address. Suppose we assign the address of variable var to a variable ptr.

Figure: Pointer as a variable

The actual address of a variable is system dependent. During compilation and linking, addresses are assumed to be relative to some base address, usually 0. When the operating system loads the program in a free block, all the address are transformed with relative to address of the first memory location of the free block. Consider the following statement :
ptr = &code;

It will assign the number 1500 to the variable ptr.

Syntax for declaring pointer variable is :


type *ptr_name;

Where type is a pre-defined or user-defined data types and indicates that the pointer will point to the variables of that specific data type, and character * indicates that variable is a pointer variable. For example the statement
int *ptr1;

Declares a pointer varieble ptr1 that can point to an integer type variable.

Once a pointer has been assigned the address of variable, the question remains as how to access the value of the variable using the pointer. This is done using indirection operator(*). Consider the following statements
: int *ptrX, x = 10, y; ptrX = &x; y = *ptr X; cout << \nValue of variable x = << x; cout << \nValue of variable pointed to by ptrX = << *ptrX; cout << \nAddress of variable x = << ptrX; cout << \nValue of variable y = << y << \n; :

// //

Program to illustrate the use of address of and indirection operators

#include <iostream.h> void main() { int *ptrX, x = 10, y; ptrX = &x; y = &ptrX; cout << \nValue of variable x = << x; cout << \nValue of variable pointed to by ptrX = << *ptrX; cout << \nAddress of variable x = << ptrX; cout << \nValue of variable y = << y << \n; }

A pointer is a variable that holds the address of another variable. We can have a variable that in turn holds an address of another variable. This type of variable will be known as pointer to pointer. A pointer to a pointer will be declared as:
int **ptr;

The value pointed to by a pointer to another pointer will be accessed as:


**ptr;

// Program to illustrate the use of double indirection #include <iostream.h> void main() { int a = 5, *ptrA, **ptrPtrA; ptrA = &a; cout << \nAddress of a = << &a; cout << \nValue of a = << a; cout << \nAddress of ptrA = << &ptrA; cout << \nValue of ptrA = << ptrA; cout << \nValue pointed to by ptrA = << *ptrA; cout << \nAddress of ptrPtrA = << &ptrPtrA; cout << \nValue of ptrPtrA = << ptrPtrA; cout << \nValue pointed to by ptrPtrA = << **ptrPtrA; cout << \n; }

STATIC MEMORY ALLOCATION


A situation where the amount of memory required is known before hand, and the compiler then can determine the memory requirements for the data as well as the instructions, in such a situation, memory allocation is known as static memory allocation.

DYNAMIC MEMORY ALLOCATION


When the amount of memory is not known before hand for a particular data item, then it is allocated at the execution time, i.e. when the program is running. In such a situation, memory allocation is known as dynamic memory allocation.

C++ language provides a set of operators called dynamic memory management operators to allocate and de-allocate memory at execution time, i.e. dynamically. new operator delete operator

The new operator allocates the memory and always returns a pointer to an appropriate type. The new operator is defined as:
type * new type [ size in integer ] ;
The following illustrates its use:
int *intPtr; intPtr = new int [100];

Allocates memory block of 200 bytes, 2 bytes for one integer value, total of 100 integers. The new operator also permits the initialisation of memory locations during allocation. The syntax for doing so is:
type *ptrVar = new type ( InitialValue);

The delete operator is a counterpart of new operator and it deallocates memory allocated by the new operator back to the free poll of memory. The syntax of delete operator is defined as:
delete ptrVar;
Where ptrVar can be a simple pointer variable or the name of the array of pointer to all types excepts class type. However, if ptrVar is an array of pointers to objects then we have to use the delete operator as shown below:
delete ptrVar[]; or delete [] ptrVar;

The second form is very handy if we want to deallocate more that one array with single use of delete operator.

We can use pointers for structure variables. Consider the following declarations:
struct EMPLOYEE { int code; char name[20]; int deptCode; float salary; }; EMPLOYEE emp, *empPtr;

These declarations create user-defined data type and give it name EMPLOYEE. It also declares emp as variable of type employee and empPtr as pointer variable to type employee. Now the following statement
ptr = &emp1;

Can be used to assign the address of variable emp1 to pointer variable ptr.

You may expect that the elements can be accessed as shown below:
*ptr.code *ptr.name *ptr.dept_code *ptr.salary

But this approach will not work as the dot operator . has higher priority than the indirection operator *. The correct way is to write as:
(*ptr).code (*ptr).name (*ptr).dept_code (*ptr).salary

The syntax for accessing members of structures using arrow operator is:
ptr->vname

#include <iostream.h> using namespace std; class cl { int i; public: cl(int j) { i=j; } int get_i() { return i; } }; int main() { cl ob(88), *p; p = &ob; // get address of ob cout << p->get_i(); // use -> to call get_i() return 0; }

Figure: Linear linked list of integer values with nodes


typedef struct nodeType { int info; struct nodeType *next; } NODE; NODE *start;

Figure: Binary tree


typedef struct nodeType { struct nodeType *left; int info; struct nodeType *right; } BNODE; BNODE *root;

Figure: Undirected graph


#define MAX 50 typedef struct nodeType { int vertex; struct nodeType *link; } node; node *adj[MAX];

Figure: Adjacency list for graph

POINTER TO AN OBJECT
When a pointer is initialized with the address of an object, then its members can be accessed using arrow -> operator.
#include <iostream.h> using namespace std; class cl { public: int i; cl(int j) { i=j; } }; int main() { cl ob(1); int *p; p = &ob.i; // get address of ob.i cout << *p; // access ob.i via p return 0; }

POINTER TO A MEMBER
To obtain address of a member, the address of & operator is used along with fully qualified member name. A class member pointer is declared using the operator ::* , acombinatio of two characters without any space. Consider the following class:
class Sample { private: int m; // . . . public: void show() // . . . };

Pointer to data member m will be declared and initialized as:


int Sample: :* intPtr = &Sample: :m ;

#include <iostream.h> using namespace std; class cl { public: cl(int i) { val=i; } int val; int double_val() { return val+val; } }; int main() { int cl::*data; // data member pointer int (cl::*func)(); // function member pointer cl ob1(1), ob2(2); // create objects data = &cl::val; // get offset of val func = &cl::double_val; // get offset of double_val() cout << "Here are values: "; cout << ob1.*data << " " << ob2.*data << "\n"; cout << "Here they are doubled: "; cout << (ob1.*func)() << " "; cout << (ob2.*func)() << "\n"; return 0; }

All non-static member functions of an object have access to a special pointer named this. The this pointer holds the address of the object whose member function is invoked.
//Program to demonstrate that this pointer is passed as //implicit first argument to a member function #include<iostream.h> #include<iomanip.h> class Sample { private: int a; int b; public: void showAddress () { cout<< endl << My objects address is <<this << endl; } }; void main() { Sample s1,s2,s3 //create objects s1.showAddress(); // call member function s2.showAddress(); s3.showAddress(); }

Like structures, there are the classes where atleast one of the data members is a pointer to itself. These types of classes are useful for building complex data structures.

class List { private : int data; List *next; public: // . . . Member functions };

PROBLEM OF DANGLING/WILD POINTERS


The most common problem with pointers is that the programmer fails to initialize a pointer with a valid address. Such an initialized pointer, referred to as dangling/wild pointer, can end up pointing anywhere in memory that may include the program code itself or to the code of the operating system. When the system stop responding, we say the system has hanged up and the only option left is to reboot the system. Therefore, care must be taken to initialize pointers with valid address.

PROBLEM OF NULL POINTER ASSIGNMENT


One particular situation that happens is when the pointer points to address 0, which is called NULL. When it happens and no catastrophic situations had occurred, then the system will display a message Null pointer assignment on termination of the program.
//Program to illustrate the cause of NULL pointer #include<iostream.h> // global pointer variable , initialized to 0 int *intPtr; void main() { *intPtr = 200; //write value on 0 address cout << \n Value stored at address o = << *intPtr; }

PROBLEM OF MEMORY LEAK


Another very serious problem with pointers is that of memory leak. Memory leak is a situation where the programmer fails to release the memory allocated at run time in module. Therefore, care must be taken to release the allocated memory block in a module where memory was allocated.
// Program to illustrate the cause of memory leak #include <iostream.h> void main() { . . . . . fun (); // invoke function named fun . . . . . } void fun() { int *intPtr; // allocate memory for n integer numbers intPtr = new [n*sizeof(int)]; // work on the allocated block }

PROBLEM OF ALLOCATION FAILURES


Allocation failure is a situation when the program through new operator request for a block of memory and the operating system could not fulfill the request of the program because the sufficient memory may not be available in the free pool of memory. Therefore, the programmer should take care of allocation failures and provide a safe exit in their programs on such failures.
// Program to illustrate the allocation failure and // the way it should be handled #include <iostream.h> void main() { int *intPtr; // allocate memory for n integer numbers intPtr = new [n*sizeof(int)]; if ( intPtr == NULL ) { cout << \nUnable to allocate memory . . . \n; return; } // work on the allocated block delete intPtr; // return the memory }

Potrebbero piacerti anche