Understand use of Pointers (*) in C and C++


Reading time: 35 minutes | Coding time: 10 minutes

We know that every instruction we give to the computer or every variable we define or every data we input must be stored in the memory of the computer so that it can be processed. This storage allocation is done in two ways:

1.Static
2.Dynamic

Static Allocation

In this, the amount of memory to be allocated is known beforehand and is reserved during compilation itself. Eg: int arr[10] - defines an array of 10 elements and allocates 10 * sizeof(int) space.

Dynamic Allocation

In this, the amount of memory is not known beforehand and is allocated during run time, that is, when the program is actually running. Eg: In a Car Parking database of a shopping mall, we do not know the exact number of cars that will be visiting our mall throughout the day.

Pointers Facilitate this dynamic allocation

What is a Pointer

A pointer in C and C++ is a variable that contains a memory address which is usually the address/ location of another variable in the memory.

So, for example, if I say the pointer variable 'ptr' points to variable x, I mean that 'ptr' holds the memory location or the exact address where x is stored in the memory. The address is usually a hexadecimal address.

The pointers are one of the most unique, useful and strongest feature of C++. They allow us to directly access the memory of the computer.

Significance of Pointers in C++

  1. Pointers provide us a way in which the memory location can be directly accessed and thus be manipulated in the way we require.
  2. Pointers support C++'s dynamic allocation routines.
  3. Pointers can improve the efficiency of various inbuilt routines/functions.

Word of Caution

Although pointers provide us this powerful feature of accessing the memory, however, we must be careful while using them. Incorrect use of pointers can effect the program in inexplicable and complex ways.

Declaration and Intialisation of Pointers

Pointers are declared in pretty much the same way we declare variables in C++. However, in order to differentiate, we make use of the character '*'.

General form of declaration-

type* pointer_name;

Description:

  1. 'type' indicates the data type to which this pointer will point to. Eg: an integer pointer can only point to int variable, a char pointer can only point to char variable and so on.

This means that pointers are data type specific.

An int pointer cannot point to a float variable and vice-versa. Same thing applies to all data types.
2. 'pointer_name' is any valid pointer name just like we name variables. All rules used for naming of idetifiers in C++ apply here as well.

Eg:

  1. int* ipter; //creates an integer pointer
  2. char* cpter; //creates a char pointer
  3. float* fpter; //creates a float pointer

Initialisation of Pointers

A already stated, pointer variables hold memory addreses. But how do we make a pointer point to a variable, that is, how can we access its memory address to store it in the pointer variable?

This is where the unary operator & comes in.

Pointers revolve around the two operators: * and &

& - This is the operator which when placed before any variable returns its memory address which we can store in our pointer.

* - While this is used to declare a pointer also, however, when it is used with a pointer that has already been declared, it returns the value of the variable that is stored at the location to which the pointer is pointing to.

To understand the above two operators, consider the example-
Let us say we have a variable i, whose value = 25 and whose address = 10500(assume). Let us see what happens when we write the following lines of code-

int i = 25;

Normal variable declaration

int* iptr;

Declaration of pointer as discussed above. Note that here, * is used for declaration purpose.

iptr = &i;

Here, & operator is placed before i. Therefore, it will return the address of i which is 10500. This address gets stored in the pointer variable iptr.This is the initialisation step of pointer - iptr.

cout<<*iptr;

Here,* is being used with a pointer that has already been decalared and initialised. iptr hold 10500 which is the address of variable i. i holds value 25. Hence, this statements outputs 25.

Important-

The operand of '&' operator is an ordinary variable.
The operand of ' * ' will be a pointer variable always.

The operator * is used for dereferencing the pointer, that is, accessing the original value.
The operator & is used for referencing the address of a variable.

Pointer Arithmetic

For normal varibales like int/float, any type of mathematical operation can be applied on them. For pointers, only addition and subtarction can be used.

Rule of pointer arithmetic:

In pointer arithmetic, all pointers increase/decrease by the length (size) of the data type they point to.

This means that if we write:

int* iptr;
iptr += 2;

Here, we want to add two to iptr. However, we will not literally add 2. Writing the above will make iptr point to the second element of iptr's type.

That is, literally, we add the size of int twice to the address stored in iptr.

Eg: if iptr had address 1050, then iptr + 2 becomes:

iptr + (size of two integers) or iptr + 2(size of int) which is equal to 1050 + 2(4) = 1058. //size of int is generally 4 bytes.

1058 is the new address we get. By writing *(iptr + 2), we can access the value at 1058.

A more clear understanding can be made with the following picture-

p_ari

Notice, how the address increments by 4 as we keep on adding 1 to ptr because ptr is an integer pointer.

Similarly, by decrementing the pointer value, each time, the same operation depicted above will be applied. Only this time, we will subtract the size of data type.

eg:

iptr -= 2;

= 1050 - 2(4) = 1042.
1042 is the new memory address.

Dynamic Allocation and Pointers:

As already stated, pointers are used for dynamic allocation. The operators that facilitate this process are - new and delete.

new - The operator new is used for creating objcts/variables of all types that are to be allocated at run time.
The general syntax:

pointer_variableName = new int; //or any other data type.

The data type of pointer name and data type on RHS must be the same.
eg:

int*iptr;
iptr = new int;

or

int*iptr = new int;

Both the above statements behave in exactly the same way. Second form is just shorter to write.

delete - This operator is used to delete or deallocate dynamically allocated memory at the end of the program.
Word of Caution:
It is very important to deallocate all dynamically allocated memory before the program ends. Failing to do so caused memory leaks. This means that each time the program will run, it will keep on allocating memory until we run out of all storage space. Hence, deallocating is important.

To deallocate, write:

delete pointer_variableName;

eg:

delete iptr;

Pointers and Arrays:

Pointers are quite closely connected to arrays. C++ treats the name of the array as a pointer. That is, if we write:

int arr[10];

arr is basically treated as a pointer. arr stores the address of the first element of the array, that is:

arr[0]

Code description-

int *a;
int age[10];
cout<<"Enter values for age:";
for(int i = 0; i < 10; i++)
{
    cin>>age[i];
}
a = age;
//check if both *a and *age have same values or not-
cout<<"a points to:"<<*a<<endl;
cout<<"age points to:"<<*age;

Input:

3 7 4 9 7 10 6 7 2 1

Output:

3
3

Both a and age point to:

age[0]

Thus, age which is the array name is essentially a pointer pointing to age[0].

Thus, because age is a pointer, hence writing

cout<<age[3];

and writing

cout<<*(age+3);

mean the same. Both produce output as 9. Thus, essentially, all pointer rules apply to the array name.

Applications of Pointers

  1. Pointers are used for passing function arguments by reference. Passing by reference means that no copy of the arguments is created within the function and the actual values are operated upon.

For eg:

#include <iostream> 
using namespace std; 

void swap(int* x, int* y) 
{ 
    int temp = *x; 
    *x = *y; 
    *y = temp; 
    cout<<x<<" "<<y<<; 
}

int main() 
{ 
    int x = 10, y = 20; 
    swap(&x, &y); 
    cout << x << " " << y << endl; 
    return 0; 
}

Ouput:

10 20
10 20

Here, values of x and y are swapped totally and not just within the function.

  1. Implementing data structures: Data structures such as linked lists, trees etc are implemented using pointers in C and C++.

  2. System Level access and programming: Various internal routines are implemented using pointers for speedy access. For eg: the system essentially accesses array elements using pointers.

With this, you will have a complete basic idea of using pointers in C and C++.