Skip to main content

Pointers.

I have already introduced pointers in the C++ Derived Data Types post, But, here I will be showing some practical examples and at the end of this slide, you will be understanding pointers like they are, obvious to you.
So, let' start by reminding you the basic syntax :- <data type> *<name_of_pointer>;
Below is the simple program for pointer declaration and initialization.

#include<iostream>
using namespace std;
int main(){
    int a = 20;
    
    
    int *b;     // Declaration of pointer b
    b = &a;     // Initialization of pointer b (& is used to extract the address of a)


    int *c = b; // Initialization of pointer c to pointer b

    cout << a << endl << b << endl << c << endl;
}

Okay, after reminding the basic syntax of pointers, you have to memorize the reason why we generally use pointers, I have already discussed that also, but, let me briefly describe it.

One of the memory section in our Computer memory named Heap Memory is not usable directly by our computer and we require to use the pointers to store our data to this memory for using it, But When we use it, We allocate some memory in Heap, which has to be freed when that memory has served its part.

Allocating Memory on heap is easy task in C++, and to do so we use new Operator. But, one more thing to see is that whenever you create a pointer, pointer is always present in the stack memory (What?;🤦‍♀️), I mean to say pointer itself present inside the stack memory while the data inside pointer i.e. the memory address is the address of some memory in the heap memory. To clear yourself see the below diagram.

Hope this simple pictorial representation could clear your doubt if you have any.
(NOTE- Here object could be anything like array, character, user defined class etc). 

One of the most significant use of pointer is that, You can even allocate memory for some object at runtime (read previous posts, if you haven't).
Below Program shows, how to create 1D array and 2D array of desired size using pointers.
#include<iostream>
using namespace std;

int main(){

    int si;
    cout << "Enter size of OneD array : "; cin >> si;
    int *OneD;
    OneD = new int[si];     // syntax for creating array of size "si"

    int row, col;
    cout << "Enter row and col for TwoD array"; cin >> row >> col;
    int **TwoD;

    TwoD = new int*[row];        //   -|
    for(int i = 0; i< row; i++) //     |    Syntax for creating row*col matrix/ 2darray.  
        TwoD[i] = new int[col]; //    -|


    return 0;
}

Now let me explain, what is **TwoD;?

Actually it is a pointer to pointer, let's see it through again a simple diagram.

From, this simple diagram the picture of declaring dynamic arrays where only pointer reside in the stack while row and column all are present inside the heap should be clear.

NOTE - Point to be noted here is that in the line TwoD = new int*[row]; , I wrote int*[row] not int[row], the reason is that, I need 1D array of pointers, while each pointer in this array in return points array of col.

As we have cleared the picture of pointers let's discuss, why pointer is sometimes very dangerous to use, Yes, You guessed right, The main problem of memory leak and undefined pointer(NULL pointer), could make our program to crash at first place. 

Now, you must be thinking if pointer are such dangerous, if not handled properly, why not C++ provide some built-in method to avoid de-allocation issue of pointers, but unlike Languages like Java, Python, C# etc where we are provided the built-in garbage collector, which deallocates memory automatically when not required, C++ also provide us some useful tools which are often called Smart Pointers.

But first see the following program.

#include<iostream>
using namespace std;
void fun(){
    int *p = new int[1000];
}
int main(){

    while(true){
        fun();
    }
    return 0;
}

Do, you see, what's wrong here? If not follow me.

In main() I have a loop which is always true, and in the loop, I am calling fun().

Now, let's see what is happening in fun(), here I am declaring p which is a pointer to integer and it is allocating array of 1000 integers. Now, you must be thinking there is nothing wrong here. But see clearly the loop will be going infinitely and the Heap Memory will be always be getting allocated for 1000 integers (for my compiler it's approx 4 KB), although the scope of pointer p is only in function fun() i.e. after each call the pointer p will always get deleted, but remember that memory that we allocated will not be get freed and after a certain time of execution of the above program, the program will throw an instance of bad_alloc() exception which means there is no memory left in Heap to allocate, It's scary AF;☹.

Smart Pointer is something that we could use to let the Compiler know that it should automatically handle this thing, So, that we don't require to de-allocate every time.

Let's discuss all types of Smart Pointers.

  • unique_ptr
  • shared_ptr
  • weak_ptr
  • auto_ptr
As you can see I have written 4 types here, but that auto_ptr was the older one or you can say the prototype version of unique_ptr, it means unique_ptr is the upgraded version of auto_ptr, so we don't require to discuss auto_ptr here.

Unique Pointer or unique_ptr.

The name itself describe the article itself, the word unique is meant the one pointer for one object, or if you have done math, it is one to one relation.
Using the same program given above by replacing simple pointer with unqiue_ptr.

#include<iostream>
#include<memory>
using namespace std;
void fun(){
    unique_ptr<int> p(new int[1000]);
}
int main(){

    while(true){
        fun();
    }
    return 0;
}

Now, it's the program with same functionality, but now try to execute this one, you will not get any exception of bad_alloc(), because memory is getting deallocated automatically, 

NOTE- In line unique_ptr<int> p(new int[1000]); I didn't used assignment operator because it is a parameterized constructor (We shall look at this in Classes concept in future), and also see clearly I wrote p not *p, because the definition of unique_ptr automatically makes it a pointer. 

But remember that in unique pointer only one pointer can point to an object, and if you want another pointer to point you have to use std::move() utility for doing so. See the program below.

#include<iostream>
#include<memory>
using namespace std;
int main(){

   unique_ptr<int> p1(new int(10000)); 
   
   // Now I want a another pointer that should 
   // point to same data where p1 is pointing

   unique_ptr<int> p2=p1;      // Wrong because two pointer can't point on same object

   unique_ptr<int> p3(move(p1));    // Right because it first deletes p1 and then assign
                                    // value to p3

    return 0;
}

Shared and weak pointer doesn't require that much explanation, so, I will be just giving a brief explanation.

Shared Pointer or shared_ptr

Shared pointer is little different than unique_ptr, the difference is obvious by reading their names, as unique pointer can only points to one object, shared pointer on other hand give us flexibility to use any number of pointers to point on one object, like Many to One relationship.
You can take same example given above, but remember the move utility is not used with shared pointers.
You can get the counting of pointers pointing to same object. See below program:-

#include<iostream>
#include<memory>
using namespace std;
int main(){

   shared_ptr<int> p1(new int(10000)); 
   
   // Now I want a another pointer that should 
   // point to same data where p1 is pointing

   shared_ptr<int> p2=p1;
   shared_ptr<int> p3=p1;

   cout << p1.use_count() << endl;  // To see how many pointing to same object

   return 0;

}

One thing I want you to notice is that if you have read my previous articles I have said that pointers uses arrow(->) operator to access the member functions but, as you can see clearly, I used dot(.) operator while writing p1.use_count(), even if I have previously said that p1 is a pointer. To understand this, you can think like, if you declare a smart pointer pointing to some object, you need to use arrow operator to access member functions of that object, but to access member function of smart pointer class itself, you don't require (->) operator, i.e. you could simply use dot(.) operator.

Weak Pointer or weak_ptr

It is similar to shared pointer i.e. you can have more than one pointer to same object, but it doesn't count how many of them are there, unlike in shared pointer, where we can get number of pointer to same object using .use_count() method.

Pointer Arithmetic :-

Now, let's take a brief look at pointer arithmetic, I will not discuss it as a whole concept, because, I wanted to combine with the concept of Iterators in c++, which we shall look in future.
I am taking a very big assumption that the person reading this blog is familiar with basic arithmetic operations 😂, but let's see what is different in pointer arithmetic (nothing different in my senses). Just look at the below program and everything will be clear to you.

#include<iostream>
using namespace std;
int main(){

    int arr[] = {1,2,3,4,5,6,7,8,9,0}; 

    /*
    I will try to output every element of the 
    array with the help of pointer arithmetic
    and not using loop
    */

    int *second = (arr + 1);

    cout << "first element " << *arr << endl;
    cout << "second element " << *(second) << endl;
    cout << "third element " << *(++second) << endl;
    cout << "fourth element " << *(++second) << endl;
    cout << "fifth element " << *(++second) << endl;
    cout << "sixth element " << *(++second) << endl;
    cout << "seventh element " << *(++second) << endl;
    cout << "eight element " << *(++second) << endl;
    cout << "ninth element " << *(++second) << endl;
    cout << "tenth element " << *(++second) << endl;
    cout << "Eleventh element " << *(++second) << endl;     // Wrong as there are only 10 elements
                                                            // So, we get garbage value 
                                                            // printed out, because the pointer
                                                            // is pointing to some memory address which is not
                                                            // initialized with some useful data

    return 0;    
}

If you didn't get the above program it's okay, for the first time.
So, let's break it down as always we do. All the below points are very important
  • So, let's start by reminding the phrase I previously talked about, i.e. the identifier of an array is actually a pointer.
  • Dereference Operator (*)- I have introduced this operator in operators section of this blog, and also you are seeing this continuously, throughout this section. Suppose you have pointer and you wrote a line like this cout << yourpointer << endl; , What do you think it will print, the data inside the pointer(i.e. some memory address) or the data at that memory address. Yes, it prints data inside pointer, but to print the data at the memory address, you have to use dereference operator i.e. cout << *(yourpointer) << endl;  (asterik symbol) as a unary operator.
  • I have used an extra pointer "second" which is initialized to the address of the second element of the array.
  • The pointer is changing it's data by pointing to the address of the next element, each time I used ++second.
  • At last I made my pointer to reach a pointer where it is pointing to some address which is out of the scope of our array.
(Try to read pointer arithmetic again, if you didn't get it, and if it is still confusing ask your doubts in the comments).

I will also explain function pointer when we will be covering advance topics in C++, until then keep reading.

Stay tuned for the upcoming content. For any query leave a comment below.

References.
  • NA

Comments

Popular posts from this blog

Number Systems (Binary and Decimal Number Systems).

We are surrounded with Numbers.  For example a human being has 2 ears, 2 legs(generally) and one nose. These all are nothing but numbers. Now, one might ask why do we need to study numbers for c++ programming. Let me answer this one first. In the previous blog I discussed that every computer works on machine language i.e. 0s and 1s, everyone know 0 and 1 are numbers. Ok, done, But what the word "Systems" doing here? What is meant by number systems. Let's see. We all have studied about the numbers from 0 to 9 i.e. 0,1,2,3,4,5,6,7,9 and we very well know that every other number can be derived from these number except infinity(no one knows what's that). for example one thousand twenty two is 1022.  This number system that we have studied is called Decimal Number System.  Why, Decimal? Because this number system contains 10 different symbols.  (In Greek Deca or Deka means 10 and this words is derived from Deca/Deka). Ok, Now we know what is decimal number system and why...

Practice Problems #1.

Below are 6 problems related to arrays, decision making statements etc. No solution will be provided for these problems except Bonus Problem. Problem 1 - Your program should print  "The weather is Good" if today's temperature is greater than 20 degree and less than 25 degree,  "The weather is little cold" if today's temperature is less than 20 degree and greater than 15 degree,  "The weather is cold" if today's temperature is less than 15 degree. "The weather is little warm" if today's temperature is greater than 25 degree but less than 30 degree. "The weather is warm" if today's temperature is greater than greater than 30 degree and less than 40 degree. "The weather is really hot" if today's temperature is greater than 40 degree. Try, to not to confuse yourself with all these statements and print accordingly to the condition matching the user's input. Problem 2 - Try to create a program with foll...

C++ Built-in Data types.

Before diving into definition of various Data Types, let's first discuss something about memory. Below is the block diagram of memory(ram) where all the data is temporarily stored before execution. Memory. The lower area of this diagram is referred as Low Memory address and upper area of this diagram is referred as High Memory address. Now let's briefly discuss each of the segments, one by one. Code Segment - The segment of memory where the text or code or your file is stored temporarily is referred as code segment. For example the main function, the function that we defined etc. Data Segment  - Data segment is of two types  Initialized data segment or simply data segment - The variables that are declared and initialized in our program are stored here. Uninitialized data segment .- The variables that are just declared or have value zero and not in use are stored here. Heap - Heap is a storage where generally dynamic memory allocation takes place with the help of pointers. If...