Menu

Saturday, 4 July 2015

POINTERS

5.1 Introduction:

Pointers are variables that hold address values.  Pointers are defined using an asterisk (*) to mean pointer to.  A data type is always included in pointer definitions, since the compiler must know what is being pointed to, so that it can perform arithmetic correctly on the pointer.  We access the thing pointed to using the asterisk in a different way, as the indirection operator, meaning contents of the variable pointed to by.

5.2 Addresses and Pointers:

The ideas behind pointers are not complicated. Here’s the first key concept: Every byte in the computer’s memory has an address. Addresses are numbers, just as they are for houses on a street. The numbers start at 0 and go up from there-l, 2, 3, and so on. If you have 640K of memory, the highest address is 655,359; for 1 MB of memory, it is 1,048,575.

Your program, when it is loaded into memory, occupies a certain range of these addresses. That means that every variable and every function in your program starts at a particular address.

2.3 The Address Of Operator &:

You can find out the address occupied by a variable by using the address of operator &. Here's a short program that demonstrates this:

// address of variables
# include<iostream.h>
void main ( )
{
     int var1 = 11;                      // define and initialize
     int var2 = 22;                      II three variables
     int var3 = 33;

     cout << endl << &var1      II print out the addresses
             <<endl <<&var2        II of these variables
 <<endl <<&var3;
}

This simple program defines three integer, variables and initializes them to the values 11, 22, and 33. It then prints out the addresses of these variables. The actual addresses occupied by the variables in a program depend on many factors, such as the computer the program is running on, the size of the operating system, and whether any other programs are currently in memory. For these reasons you probably won't get the same addresses we did when you run this program. Here's the output on our machine:

Ox8f4ffff4                   address of varl

Ox8f4ffff2                   address of var2
Ox8f4ffffO                 address of var3

The address of a variable is not at all the same as its contents. The contents of the three variables are 11,22, and 33. The << insertion operator interprets the addresses in hexadecimal arithmetic, as indicated by the prefix Ox before each number. This is the usual way to show memory addresses.

The addresses appear in descending order because automatic variables are stored on the stack, which grows downward in memory. If we had used external variables they would have ascending addresses, since external variables are stored on the heap, which grows upward.

2.4 Pointer Variable:

Address by themselves are rather limited. It’s nice to know that we can find out where things are in memory, but printing out address values is not all that useful. The potential for increasing our programming power requires an additional idea: variables that hold address values. Addresses are stored similarly as variables of different data types. A variable that holds an address value is called a pointer variable or simply a pointer.

2.5 Declaring and Initializing Pointers:


Let's examine the process of declaring pointers. A computer needs to keep track of the type of value to which a pointer refers. For example, the address of a char looks the same as the address of a double, but char and double use different numbers of bytes and different internal formats for storing values. Therefore, a pointer declaration must specify what type of data it is to which the pointer points. For example, the statement.

int  * p_updates;

 

This states that the combination * p-updates is type int. Because the * operator is used by applying it to a pointer, the p_updates variable itself must be a pointer. We say that p_updates points to type int. We also say that the type for p_updates is pointer-to-int or, more concisely, int *. To repeat p_updates is a pointer (an address}, and *p-updates is an int and not a pointer.


Incidentally, the use of spaces around the * operator are optional. For example:

int* ptr;

This emphasizes the idea that int* is a type, pointer-to-int. Where you put the spaces makes no difference to the compiler. Be aware, however, that the declaration

int* p1,p2;

Creates one pointer (p1) and one ordinary int variable (p2)
If you define more than one pointer of the same type on one line, you need only insert the type-pointed-to once, but you need to place an asterisk before each variable name:

char * ptr1, * ptr2, * ptr3;       // three variables of type char*

Or you can use the asterisk-next-to-the-name approach

char *ptr1, *ptr2, *ptr3;          // three variables of type char*

Pointers Must Have a Value: An address like OxHf4ffff4 can be thought of as a pointer constant. A pointer like ptr can be thought of as a pointer variable. Just as the integer variable var1 can be assigned the constant value 11, so can the pointer variable ptr be assigned the constant value Ox8f4ffff4.

When we first define a variable, it holds no value (unless we initialize it at the same time) it may hold a garbage value, but this has no meaning. In the case of pointers, a garbage value is the address of something in memory, but probably not of something that we want. So before a pointer is used, a specific address must be placed in it.

ptr = &var1;                put address of var l in ptr.

Following this the program prints out the value contained in ptr, which should be the same address printed for &var1.

To summarize: A pointer can hold the address of any variable of the correct type; However, it must be given some value, otherwise it will point to an address we don't want it to point to, such as into our program code or the operating system. Wrong pointer values can result in system crashes and are difficult to debug, since the compiler gives no warning.

2.6 Accessing the Variable Pointed to:

Suppose that we don’t know the name of a variable but we do know its address. We can access the contents of the variable, by using a special syntax (indirection operator) to access the value of such variable.

# include <iostream.h>

void main( ) 
{
int var1 =11;                //two integer variables
int var2 = 22;
int* ptr;                       // pointer  to integers
ptr = &var1;                // pointer points to var1
cout<<endl<<*ptr;      // pointer contents of pointer (11)
ptr = &var2;                // pointer points to var2
cout<<endl<<*ptr;      // pointer contents of pointer (22)
}

When an asterisk is used in front of a variable name, as it is in the * ptr expression; it is called the indirection operator. It means the value of the variable pointed to by. Thus the expression *ptr represents the value of the variable pointed to by ptr. When ptr is set to the address of var1, the expression *ptr has the value 11; since var1 is 11. When ptr is changed to the address of var2, the expression *ptr acquires the value 22, since var1 is 22.You can use a pointer not only to display a variable's value but to perform any operation you would perform on the variable directly. The asterisk used as the indirection operator has a different meaning from the asterisk used to declare pointer variables. The indirection operator precedes the variable and means value of the variable pointed to by the asterisk used in a declaration means pointer to.

int* ptr;           // declaration:
*ptr =37;         II indirection:

Using the indirection operator to access the value stored in an address is called indirect addressing, or sometimes dereferencing, the pointer: 

int  v;               II defines variable v of type int
int* p;              II defines p as a pointer to int
p = &v;            II assigns address of variable v to pointer p
v = 3;               II assigns 3 to v
*p = 3;             II also assigns 3 to V

2.7 Pointers and Arrays:

There is a close association between pointers and arrays. The near equivalence of pointers and array names stems form the pointer arithmetic and how C++ handles arrays internally. Consider the program below:

# include <iostream.h> ,

void main( )
{

     double wages[3] = {10000.0, 20000.0, 30000.0};
     short stacks[3] = {3, 2, 1};

     II Here are two ways to get the address of an array
      double * pw = wages;       II name of an array = address
      short * ps = &stacks[0];    II or use address operator

     II with array element
     cout <<"pw = " <<pw <<" *pw = " <<*pw <<"\n";
       pw = pw + 1;
       cout <<"add 1 to the pw pointer: \n';
       cout <<"pw = " <<pw <<", *pw = " <<*pw <<"\n\n”;
       cout <<"ps = " <<ps <<" *ps = " <<*ps <<"\n";
       ps = ps + 1;

       cout <<"add 1 to the ps pointer:\n";
       cout <<"ps = " <<ps <<", *ps = " <<*ps <<"\n\n”;
       cout <<"access two elements with array notation \n";
       cout <<stacks[0] <<" " <<stacks[1] <<"\n";
       cout <<"access two elements with pointer notation \n";
       cout <<*stacks <<" " <<*(stacks + 1) <<"\n";
       cout <<sizeof wages <<" = size of wages array \n";
       cout <<sizeof pw <<" = size of pw pointer \n";
}

C++ interprets the name of an array as the, address of its first element. Thus, the statement

double * pw = wages;

makes pw a pointer to type double and then initializes pw to wages, which is the address of the first element of the wages array. For wages, as with any array, we have the following equality:

wages = &wages[0] = address of first element of array

Just to show that this is no jive, the program explicitly uses the address operator in the expression &stacks [0] to initialize the ps pointer to the first element of the stacks array. Next, the program inspects the values of pw and *pw. The first is an address and the second is the value at that address. Because pw points to the first element, the value displayed for *pw is that of the first element, 10000. Then, the program adds 1 to pw. This adds 8 (EO + 8 = E8 in hexadecimal) to the numeric address value, because double is 8 bytes. This makes pw equal to the address of the second element. Thus, *pw now is 20000, the value of the second element. After this, the program goes through similar steps for ps. This time, because ps points to type short and because short is 2 bytes, adding 1 to the pointer increases its value by 2. Again, the result is to make the pointer point to the next element of the array.

Note: Adding 1 to a pointer variable increases its value by the number of bytes of the type to which it points.

2.8 Pointers and Strings:

The special relationship between arrays and pointers extends to strings. Consider the following code:

char flower[10] = "rose";
cout <<flower <<"s are red \n";

The name of an array is the address of its first element, so flower in the cout statement is the address of the char element containing the character r. The cout object assumes that the address of a char is the address of a string, so it prints the character at that address and then continues printing characters until it runs into the null character (\0). In short, if you give cout the address of a character, it prints everything from that character to the first null character that follows it. The crucial element here is not that flower is an array name but that flower acts as the address of a char. This implies that you can use a pointer-to-char variable as an argument to cout, also, because it, too, is the address of a char. Of course, that pointer should point to the beginning of a string. We'll check that out in a moment.

But first, what about the final part of the preceding cout statement? If flower actually is the address of the first character of a string, what is the expression "s are red\ n"? To be consistent with cout's handling of string output, this quoted string also should be an address. And it is, for in C++ a quoted string, like an array name, serves as the address of its first element. The preceding code doesn't really send a whole string to cout, it just sends the string address. This means strings in an array; quoted string constants, and strings described by pointers all are handled equivalently: Each really is passed along an address. That's certainly less work than passing each and every character in a string.

// Program to demonstrate arguments passed by pointer
#include <iostream.h>
void main( )
{
void centimize(double*);                    // prototype
double var = 10.0;                               II var has value of 10 inches
cout <<endl <<"var=" <<var <<" inches";

centimize(&var);                                 II change var to centimeters
cout <<endl <<"var:" <<var <<“centimeters" ;
}

void centimize(double* ptrd)
{
*ptrd *= 2.54;                                     II *ptrd is the same as var
}

The function centimize ( ) is declared as taking an argument that is a pointer to double:

void centimize(double*)                     II argument is pointer to double

When main( ) calls the function it supplies the address of the variable as the argument:

            centimize(&var);

Remember that this is not the variable itself, as it is in passing by reference, but the variable's address.

Because the centimize ( ) function is passed an address, it must use the indirection operator, *ptrd, to access the value stored at this address:

            *ptrd *= 2.54;                         II multiply the contents of ptrd by 2.54

Is the same as

            *ptrd = *ptrd * 2.54; II multiply the contents of ptrd by 2.54

where the stand-alone asterisk means multiplication.

Since ptrd contains the address of var, anything done to *ptrd is actually done to var. Passing a pointer as an argument to a function is in some ways similar to passing a reference. They both permit the variable in the calling program to be modified by the function. However, the mechanism is different. A reference is an alias for the original variable, while a pointer is the address of the variable.

2.9 Using new to create Dynamic Structures:

You’ve seen how it can be advantageous to create arrays during runtime rather than compile time.  The same holds true for structures. You need to allocate space for only as many structures as a program needs during a particular run.  The new operator is the tool to use.  With it, you can create dynamic structures. “Dynamic” means the memory is allocated during runtime, not during compilation. Using new with structures has two parts: creating the structures and accessing its members. To create a structure, use the structure type with new. For example, to create an unnamed structure and assign its address to a suitable pointer, you can do the following:

inflatable * ps = new inflatable;  // consider inflatable is am structure

This assigns to ps the address of a chunk of free memory large enough to hold a structure of the inflatable type. The tricky part is accessing members. When you create a dynamic structure, you can't use the dot membership operator with the structure name, because the structure has no name. All you have is its address. C++ provides an operator just for this situation: the arrow membership operator(->).This operator, formed by typing a hyphen and then a greater-than symbol, does for pointers to structures what the dot operator does for structure names. For example, if ps points to a type inflatable structure, then ps -> price is the price member of the pointed-to structure.

This operator obtains memory from the operating system and returns a pointer to its starting point. Consider the program shows how new is used:

# include <iostream.h>
# include <string.h>                II for strcpy()
void main( )
 {
     char* str = "Idle hands are the devil’s workshop.";
      int len = strlen(str);                        II get length of str
      char* ptr;                                       II make a pointer to char
      ptr = new char[len+1];                  II set aside memory: string + '\0'
       strcpy(ptr, str);                             II copy str to new memory area ptr
       cout <<endl <<“ptr=" <<ptr;       II show that str is now in ptr
       delete ptr;                                     II release ptr 's memory
}

The expression

ptr = new char[len+1];

returns a pointer that points to a section of memory just large enough to hold the string str, whose length len we found with the strlen ( ) library function, plus an extra byte for the null character '\0' at the end of the string. Remember to use brackets around the size; the compiler won't object if you use parentheses, but the results will be incorrect.

2.10 Delete Operator:


If your program reserves many chunks of memory using new, eventually all the available memory will be reserved and the system will crash. To ensure safe and efficient use of memory, a corresponding delete operator that returns memory to the operating system.

delete ptr;

returns to the system whatever memory was pointed to by ptr . Actually, there is no need for this operator, since memory is automatically returned when the program terminates. However, suppose you use new in a function. If the function uses a local variable as a pointer to this memory, then when the function terminates, the pointer will be destroyed but the memory will be left as an orphan, taking up space that is inaccessible to the rest of the program. Thus it is always good practice to delete memory when you're through with it.

5.11 Pointers to Objects:

Pointers can point to objects as well as to simple data types. We've seen many examples of objects defined and given a name, in statements like

Distance dist;

where an object called dist is defined to be of the Distance class. Sometimes, however, we don't know, at the time that we write the program, how many objects we want to create. When this is the case we can use new to create objects while the program is running.

// Program to show accessing of member functions by pointer
# include <iostream.h>
class Distance
{
   private:
                int feet;
    float inches;
     public:
 void getdist( )                        // get length from user
            {
       cout <<"\n Enter feet: ";   cin >> feet;
       cout <<"Enter inches: ";     cin >> inches;
}

void showdist( )          // display distance
{  cout <<feet <<"\'-" <<inches <<'\"'; }
};

void main( )
 {
Distance dist;                          // define a named Distance object
dist.getdist( );                          // access object members
dist.showdist( );                      // with dot operator

Distance*  distptr;                   // pointer to Distance
distptr = new Distance;           // points to new Distance object
distptr->getdist( );                   // access object members
distptr->showdist( );               // with -> operator
}

This program uses a variation of the Distance class seen in previous chapters. The main ( ) function defines dist, uses the Distance member functions, getdist ( ) to get a distance from the user;  and then uses showdist ( ) to display it.

Referring To Members: The program creates another object of type Distance the new operator. To refer to a member function dot operator requires the identifier on its left to be a variable. We can deference (get the contents of the variable pointed to by) the pointer:


(*distptr).getdist( );                 // ok but inelegant 

However, this is slightly cumbersome because of the parentheses. A more concise
approach is furnished by the membership-access operator ->, which consists of a hyphen and a greater than sign:

distptr->getdist( );                               // better approach









Exercise:

  1. The structure candy contains three members. The first holds the name of the candy, the second holds the price (can be fractional) and the third holds the weight. Write a program that creates a variable of candy using the new operator.

  1. Implement the concept of creating Linked list.

  1. Write a program to insert and delete a number in a linked list.

  1. Write a program to implement the stack, using pointer.