Pointers

Function Pointer in C/C++

Function Pointers are used to store address of functions, we’ve used pointers to point to data (variables)

"Insert Images" "Insert Images" "Insert Images"

Function Pointers and Callbacks

"Insert Images" "Insert Images"

Function pointers can be passed as arguments to functions and then a function that would receive a function pointer as an argument can call back the function that this pointer will point to.

Example

#include <iostream>
using std::cout;
using std::endl;


void A()
{
    cout << "Hello World " << endl;
}

void B(void (*ptr)()) // function Pointer as Argument
{
    ptr(); // Call-Back Function that "ptr" points to
           // Call to whatever function it is pointing too
}

int main()
{
    void (*p)() = A;  // Function Pointer (points to a function) initialize with Address of A
    B(p); // Pass function pointer
}

Output:

Hello World 

Function A is getting executed, through this callback

Can Also write Code like this


#include <iostream>
using std::cout;
using std::endl;

void A()
{
    cout << "Hello World " << endl;
}

void B(void (*ptr)()) // function Pointer as Argument
{
    ptr(); // Call-Back Function that "ptr" points to
           // Call to whatever function it is pointing too
}

int main()
{
    B(A);
}

Output:

Hello World 

Question

What is the point of calling A indirectly through B in this Code?

Lets use BubbleSort:

#include <iostream>
using std::cout;
using std::endl;

void BubbleSort(int *A, int n)
{
    int i,j, temp;

    for (i = 0; i< n; i++ )
    {
        for (j = 0; j < n-1; j++ )
        {
            if (A[j] > A[j+1])
            {
                // Compare A[j] with A[j+1] and SWAP if needed
                temp = A[j];
                A[j] = A[j+1];
                A[j+1] = temp;
            }
        }
    }
}

int main()
{
    int i, A[] = {3,2,1,5,6,4};
    cout << "Array Before BubbleSorting: ";
    for (i = 0; i <6; i++ )
    {
        // Print Array
        cout << A[i];
    }
    cout << endl;
    BubbleSort(A,6);
    
    cout << "Array After BubbleSorting: ";

    for (i = 0; i <6; i++ )
    {
        // Print Array
        cout << A[i];
    }
    cout << endl;

}

Output:

Array Before BubbleSorting: 321564
Array After BubbleSorting: 123456

Now lets say we want to sort out list in decreasing order of the values of integers.

What changes will we make to the code?

Previous:

if (A[j] > A[j+1])

Updated:

if (A[j] < A[j+1])

With this comparison we are pushing the smaller number towards the higher index

After we make the comparison change our output is:

Array Before BubbleSorting: 321564
Array After BubbleSorting: 654321

Sometimes we want to sort in increasing order and sometimes we want to sort in decreasing order

How can we accomplish this? (without writing duplicate code)

There are multiply ways:

In order to avoid writing duplicate code we can pass flag to our bubblesort function.

Another Approach:

Our Sort function will take a function pointer as an arguemnt

compare

#include <iostream>
using std::cout;
using std::endl;

// Callback function should compare two integers and should return 1 if first element
// Has higher rank, 0 if elements are equal and -1 if second element has higher rank

int compare(int a, int b)
{
    if ( a > b){
        return 1;
    }
    else{
        return -1;
    }
}
void BubbleSort(int *A, int n, int (*compare)(int,int))
{
    int i,j, temp;

    for (i = 0; i< n; i++ )
    {
        for (j = 0; j < n-1; j++ )
        {
            if (compare(A[j], A[j+1]) > 0)
            {   // Compare A[j] with A[j+1] and SWAP if needed
                temp = A[j];
                A[j] = A[j+1];
                A[j+1] = temp;
            }
        }
    }
}

int main()
{
    int i, A[] = {3,2,1,5,6,4};

    BubbleSort(A,6, compare);

    for (i = 0; i <6; i++ )
    {
        cout << A[i] << " ";
    }
    cout << endl;
}

Output:

1 2 3 4 5 6 

If we change our compare function

int compare(int a, int b)
{
    if ( a > b){
        return -1;
    }
    else{
        return 1;
    }
}

After Changing our compare function our output will be:

6 5 4 3 2 1 
  • We can have one call-back function for each ranking mechanism

Another Example

int A[] = {-31,22,-1,50,-6,4}; // {-1,-4,-6,22,-31,50}

We want to increase in the order of absolute value of integers, so the negative sign will not matter and we will just take a MOD and then compare

To be able to sort we will have to write another comparison function, we will add another function called absolute_compare


#include <iostream>
using std::cout;
using std::endl;

#include <math.h>

// Callback function should compare two integers and should return 1 if first element
// Has higher rank, 0 if elements are equal and -1 if second element has higher rank

int compare(int a, int b)
{
    if ( a > b){
        return -1;
    }
    else{
        return 1;
    }
}

int absolute_compare(int a, int b)
{
    if(abs(a) > abs(b))
    {
        return 1;
    }
    else{
        
        return -1;
    }
}

void BubbleSort(int *A, int n, int (*compare)(int,int))
{
    int i,j, temp;

    for (i = 0; i< n; i++ )
    {
        for (j = 0; j < n-1; j++ )
        {
            if (compare(A[j], A[j+1]) > 0)
            {   // Compare A[j] with A[j+1] and SWAP if needed
                temp = A[j];
                A[j] = A[j+1];
                A[j+1] = temp;
            }
        }
    }
}

int main()
{
    int i, A[] = {-31,22,-1,50,-6,4}; // {-1,-4,-6,22,-31,50}

    BubbleSort(A,6, absolute_compare);

    for (i = 0; i <6; i++ )
    {
        cout << A[i] << " ";
    }
    cout << endl;
}

Output:

-1 4 -6 22 -31 50 

The elements are sorted in increasing order of their absolute values.

Memory Leaks in C/C++

  • Memory Leak is the improper use of Dynamic Memory

  • It happens when we get some memory (new) on the Heap and we do not free it (delete) when were dont using it, so our application is golding onto some unused memory on the Heap

"Insert Images"

Casino Game Code (casino.cpp)



#include<iostream>
#include<time.h>

int cash = 100;  // Global Variable

void Play(int bet)
{
    char C[3] = {'J', 'Q','K'};
    std::cout << "Shuffling...." << std::endl;
    srand(time(NULL));             // Seeding random number generator
    
    for (int i = 0; i < 5; i++)
    {
        int x = rand() % 3;
        int y = rand() % 3;
        int temp = C[x];
        C[x] = C[y];
        C[y] = temp; // Swaps characters at position x and y

    }

    int playersGuess;
    std::cout << "What is the position of queen - 1,2 or 3? ";
    std::cin >> playersGuess;

    if (C[playersGuess - 1] == 'Q'){
        cash += 3*bet;
        std::cout << "You win ! Result = " << "'"<< C[0] << " " << C[1] << " " << C[2] << "'" << std::endl;
        std::cout << "Total Cash: " << cash << std::endl;
    }
    else {
        cash -= bet;
        std::cout << "You lose !!! Result = " << "'"<< C[0] << " " << C[1] << " " << C[2] << "'" << std::endl;
        std::cout << "Total Cash = " << cash << std::endl;
    }

}


int main()
{
    int bet;
    std::cout << "Welcome to the Virtual Casino \n";
    std::cout << "Total cash = " << cash << std::endl;

    while (cash > 0)
    {
        std::cout << "What is your bet? ($) ";

        std::cin >> bet;

        if (bet == 0 || bet > cash )
        {
            break;
        }
        Play(bet);
        std::cout << "\n *************************************** \n";

    }   
}

Output

Welcome to the Virtual Casino 
Total cash = 100
What is your bet? ($) 20
Shuffling....
What is the position of queen - 1,2 or 3? 2
You win ! Result = 'J Q K'
Total Cash: 160
 *************************************** 
What is your bet? ($) 100
Shuffling....
What is the position of queen - 1,2 or 3? 1
You lose !!! Result = JQKTotal Cash = 60

 *************************************** 
What is your bet? ($) 0

Above is a sample of use using the game. Were using the memory on the stack and not allocating new memory anywhere so this program doesn’t get bigger in terms of using memory.

But if want to allocate new memory on the Heap we can rewrite our statement:

Old Code:

char C[3] = {'J', 'Q','K'};

Updated Code:

char *C = new char[3]
C[0] = 'J';
C[1] = 'Q';
C[2] = 'K';

We have created an Array on the Heap and C is a pointer to Character (Char) that is pointing to the base address of the Array.

Now what happens when we run this Code?

  • The memory consumption increases!!!!

Some amount of memory from the stack is allocated for its execution. When the program starts executing, first the main method is invoked or called. All the local variables of main will sit inside the stack frame in our code (bet) and we had a Global variable called cash!

When we play our Casino Game, our main function makes multiple calls to play function. What happens when a particular function makes calls to another function? That particular function is paused and the memory is allocated for the execution of the called function. So main function will pause and play will start to execute.

Case 1:

Character Array is on the stack, it was not created using a call to new

  • Character C sits in the stack frame

When the execution of Play() will finish, control will return back to main() and memory that was allocated for the execution of play function will be reclaimed.

Anytime a function call finishes the memory that is allocated on the stack is reclaimed! There is one stack frame corresponding to each call and as soon as that call is finished the memory is claimed back.

All the local variables get cleared each time the function call finishes.

For anything on the stack we don’t have to worry about it’s deallocation, it happens automatically when the function call finishes!

Case 2:

Character Array is on the Heap

We will still have local variable C, but this variable will be of type pointer to character, and we will create a call using the new keyword to create the array on the Heap. And this pointer (C) will point to the particular memory block.

Anything that is on the Heap has to be accessed through a pointer variable.

Now when the call to play function will finish the memory allocated for the execution will be reclaimed so all the local variables will go away. But the memory on the Heap will lie unused and unreferenced and will not be deallocated.

Anything on the Heap has to be explicitly deallocated by making the call to delete keyword!

In our game we will make multiple calls to the Play() function and each time we will create a new memory block on the Heap.

Heap is not fixed in size and our application can claim/get more memory, if were not deleting memory on the Heap then we are depleting and wasting memory which is an important resource.

Memory Leaks is nothing nbut growth of Garbage in the Heap.

Languages like Java and C#, garbage is automatically cleared from the heap, so a programmer does not have to worry about “freeing” memory.

How would we fix our code in Case 2?

At the end of the Play() function we can write the line:

delete C;

This will deallocate memory off of the Heap after each function call!

"Insert Images"