Monday 7 August 2017

POINTERS

Pointers are one of the most fundamental things to understand in the C++ programming language. So what’s a pointer? A pointer is just the address of a piece of data in memory.

Instead of passing around a whole copy of the data, you can just pass a pointer.


















MEMORY

To understand what pointers are, you’ll need to dig into the memory of the computer.
Every time you declare a variable, the computer creates space for it somewhere in memory. If you declare a variable inside a function like main(), the computer will store it in a section of memory called the stack. If a variable is declared outside any function, it will be stored
in the globals section of memory.




What are pointers for? Here are some common uses:

• Accessing array elements
• Passing arguments to a function when the function needs to modify the original argument
• Passing arrays and strings to functions
• Obtaining memory from the system
• Creating data structures such as linked lists

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—1, 2, 3, and so on. If you have 1MB of memory, the highest address is 1,048,575. (Of course you have much more.)
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.

The following Figure shows how this looks.























The Address-of Operator &

You can find the address occupied by a variable by using the address-of operator &. Here’s a
short program, VARADDR, that demonstrates how to do this:
// varaddr.cpp
// addresses of variables
#include <iostream.h>
void  main()
{
int var1 = 11; //define and initialize
int var2 = 22; //three variables
int var3 = 33;

cout << &var1 << endl //print the addresses
<< &var2 << endl //of these variables
<< &var3 << endl;
}
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.

Here’s the output on our machine:
0x8f4ffff4 ← address of var1
0x8f4ffff2 ← address of var2
0x8f4ffff0 ← address of var3

Remember that 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 following Figure shows the three variables in memory.


The << insertion operator interprets the addresses in hexadecimal arithmetic, as indicated by the prefix 0x before each number. This is the usual way to show memory addresses.

However, you might note in the output that each address differs from the next by exactly 2 bytes. That’s because integers occupy 2 bytes of memory (on a 16-bit system). If we had used variables of type char, they would have adjacent addresses, since a char occupies 1 byte; and if we had used type double, the addresses would have differed by 8 bytes.

Pointer Variables

A variable that holds an address value is called a pointer variable, or simply a pointer.

// ptrvar.cpp
// pointers (address variables)
#include <iostream.h>
void main()
{
int var1 = 11; //two integer variables

int var2 = 22;
cout << &var1 << endl //print addresses of variables
<< &var2 << endl << endl;
int* ptr; //pointer to integers
ptr = &var1; //pointer points to var1
cout << ptr << endl; //print pointer value
ptr = &var2; //pointer points to var2
cout << ptr << endl; //print pointer value
}

This program defines two integer variables, var1 and var2, and initializes them to the values
11 and 22. It then prints out their addresses. The program next defines a pointer variable in the line

int* ptr;

 The asterisk means pointer to. Thus the statement defines the variable ptr as a pointer to int. This is another way of saying that this variable can hold the addresses of integer variables.
What’s wrong with the idea of a general-purpose pointer type that holds pointers to any data
type?
If we called it type pointer we could write declarations like

pointer ptr;


The problem is that the compiler needs to know what kind of variable the pointer points to.


char* cptr; // pointer to char
int* iptr; // pointer to int
float* fptr; // pointer to float
Distance* distptr; // pointer to user-defined Distance class

and so on.

Syntax Quibbles

We should note that it is common to write pointer definitions with the asterisk closer to the
variable name than to the type.

char *charptr;

It doesn’t matter to the compiler, but placing the asterisk next to the type helps emphasize that the asterisk is part of the variable type (pointer to char), not part of the name itself.

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 0x8f4ffff4 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 0x8f4ffff4.

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. In the PTRVAR program, ptr is first assigned the address of var1 in the line


ptr = &var1; ← put address of var1 in ptr


To summarize: 

A pointer can hold the address of any variable of the correct type; it’s a receptacle
awaiting an address. 
However, it must be given some value, or it will point to an address we don’t want it to point to, such as into our program code or the operating system.
 Roguepointer values can result in system crashes and are difficult to debug, since the compiler gives no warning. 
The moral: Make sure you give every pointer variable a valid address value before
using it.
























Accessing the Variable Pointed To

Suppose that we don’t know the name of a variable but we do know its address. Can we access the contents of the variable? (It may seem like mismanagement to lose track of variable names, but we’ll soon see that there are many variables whose names we don’t know.)
There is a special syntax to access the value of a variable using its address instead of its name.
Here’s an example program, PTRACC, that shows how it’s done:
// ptracc.cpp
// accessing the variable pointed to
#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 << *ptr << endl; //print contents of pointer (11)
ptr = &var2; //pointer points to var2
cout << *ptr << endl; //print contents of pointer (22)
}

This program is very similar to PTRVAR, except that instead of printing the address values in ptr, we print the integer value stored at the address that’s stored in ptr. Here’s the output:
11

22

When an asterisk is used in front of a variable name, as it is in the *ptr expression, it is called the dereference operator (or sometimes 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 var2 is 22. Another name for the dereference operator is the contents of operator, which is another way to say the same thing.

You can use a pointer not only to display a variable’s value, but also to perform any operation you would perform on the variable directly. Here’s a program, PTRTO, that uses a pointer to assign a value to a variable, and then to assign that value to another variable:

// ptrto.cpp
// other access using pointers
#include <iostream.h>
void main()
{
int var1, var2; //two integer variables
int* ptr; //pointer to integers
ptr = &var1; //set pointer to address of var1
*ptr = 37; //same as var1=37
var2 = *ptr; //same as var2=var1
cout << var2 << endl; //verify var2 is 37
}























Remember that the asterisk used as the dereference operator has a different meaning than the asterisk used to declare pointer variables. The dereference 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: pointer to int
*ptr = 37; //indirection: value of variable pointed to by ptr

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

Here’s a capsule summary of what we’ve learned so far:

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

The last two statements show the difference between normal or direct addressing, where we
refer to a variable by name, and pointer or indirect addressing, where we refer to the same

variable using its address.

Pointer to void

Before we go on to see pointers at work, we should note one peculiarity of pointer data types.
Ordinarily, the address that you put in a pointer must be the same type as the pointer. You can’t assign the address of a float variable to a pointer to int, for example:

float flovar = 98.6;
int* ptrint = &flovar; //ERROR: can’t assign float* to int*

However, there is an exception to this. There is a sort of general-purpose pointer that can point to any data type. This is called a pointer to void, and is defined like this:

void* ptr; //ptr can point to any data type

Such pointers have certain specialized uses, such as passing pointers to functions that operate independently of the data type pointed to.

// ptrvoid.cpp
// pointers to type void
#include <iostream.h>
void main()
{
int intvar; //integer variable
float flovar; //float variable
int* ptrint; //define pointer to int
float* ptrflo; //define pointer to float
void* ptrvoid; //define pointer to void
ptrint = &intvar; //ok, int* to int*
// ptrint = &flovar; //error, float* to int*
// ptrflo = &intvar; //error, int* to float*

ptrflo = &flovar; //ok, float* to float*
ptrvoid = &intvar; //ok, int* to void*
ptrvoid = &flovar; //ok, float* to void*
}

Pointers and Arrays

There is a close association between pointers and arrays. 

// arrnote.cpp
// array accessed with array notation
#include <iostream.h>
void main()
{ //array
int intarray[5] = { 31, 54, 77, 52, 93 };
for(int j=0; j<5; j++) //for each element,
cout << intarray[j] << endl; //print value
}


// ptrnote.cpp
// array accessed with pointer notation
#include <iostream.h>
void main()
{ //array
int intarray[5] = { 31, 54, 77, 52, 93 };
for(int j=0; j<5; j++) //for each element,
cout << *(intarray+j) << endl; //print value
}

The expression *(intarray+j) in PTRNOTE has exactly the same effect as intarray[j] in

ARRNOTE, and the output of the programs is identical.



// ptrinc.cpp
// array accessed with pointer
#include <iostream.h>
void  main()
{
int intarray[] = { 31, 54, 77, 52, 93 }; //array
int* ptrint; //pointer to int
ptrint = intarray; //points to intarray
for(int j=0; j<5; j++) //for each element,
cout << *(ptrint++) << endl; //print value
}

Pointers and Functions


The PASSREF program shows passing by reference.

// passref.cpp
// arguments passed by reference
#include <iostream.h>

void main()
{void centimize(double&); //prototype
double var = 10.0; //var has value of 10 inches
cout << “var = “ << var << “ inches” << endl;
centimize(var); //change var to centimeters
cout << “var = “ << var << “ centimeters” << endl;
}
//
void centimize(double& v)
{
v *= 2.54; //v is the same as var
}

The next example, PASSPTR, shows an equivalent situation when pointers are used:
// passptr.cpp
// arguments passed by pointer
#include <iostream.h>
void main()
{
void centimize(double*); //prototype
double var = 10.0; //var has value of 10 inches
cout << “var = “ << var << “ inches” << endl;
centimize(&var); //change var to centimeters
cout << “var = “ << var << “ centimeters” << endl;
}
//

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

}

Passing Arrays

// passarr.cpp
// array passed by pointer
#include <iostream.h>
const int MAX = 5; //number of array elements
int main()
{
void centimize(double*); //prototype
double varray[MAX] = { 10.0, 43.1, 95.9, 59.7, 87.3 };
centimize(varray); //change elements of varray to cm
for(int j=0; j<MAX; j++) //display new array values
cout << “varray[“ << j << “]=”
<< varray[j] << “ centimeters” << endl;
}
//
void centimize(double* ptrd)
{
for(int j=0; j<MAX; j++)
*ptrd++ *= 2.54; //ptrd points to elements of varray

}

Since the name of an array is the array’s address, there is no need for the address operator & when the function is called:

centimize(varray); // pass array address
In centimize(), this array address is placed in the variable ptrd. 

To point to each element of the array in turn, we need only increment ptrd:
*ptrd++ *= 2.54;

Figure hows how the array is accessed. Here’s the output of PASSARR:

varray[0]=25.4 centimeters
varray[1]=109.474 centimeters
varray[2]=243.586 centimeters
varray[3]=151.638 centimeters

varray[4]=221.742 centimeters

Here’s a syntax question: How do we know that the expression *ptrd++ increments the pointer and not the pointer contents? In other words, does the compiler interpret it as *(ptrd++), which is what we want, or as (*ptrd)++? It turns out that * (when used as the dereference operator) and ++ have the same precedence. 

Here the expression is interpreted as *(ptrd++), which increments the  pointer, not what it points to. That is, the pointer is incremented first and the dereference operator is applied to the resulting address.

Pointers to Characters/String Constants :

# include <iostream.h>
 # include <conio.h> 
void main() 
{ char str1[] = "array of characters"; 
char *strptr = "pointer to character"; 
cout << endl << str1; cout << endl << strptr; 
// str1++; // throws an error-lvalue required 
strptr++; 
cout << endl << *strptr; 
cout << endl << strptr; }

Output:

Output : 

array of characters 
pointer to character 

ointer to character