Thursday, September 27, 2018

An introduction to declare, initialize and access a function pointer in C

     As we know that the pointers are variables which holds the address of another variable. Many of us might have used pointers such as integer pointer, character pointer, pointer to a structure, etc. in our usual C programming. But the use of C function pointers is very occasional. In this post, we can look at the ways to declare, initialize and access the function pointers.

What is Function Pointer:
    A function pointer is a variable, which holds the address of a function. As we know that for each variable in C, one address can be associated. This address is the memory location in main memory where the value of the variable is being stored at the run time. Like variables, each function is also has an address. Functions are sequence of instructions present in a main memory. The address of each function is the address of the first instruction of that function definition.

Function's Signature:
    Each function is having a specific signature. That is, a signature of a function is defined by the number of arguments they accept and the type of those arguments and the return type.

   For example, the below two functions have the same signatures.

   void function1 (int arg1, char arg2);
   void function2 (int val1, char val2);

   The functions "function1" and "function2" has the same signatures as they match in the number and type of arguments accepted and having the matching return type.
 
   void function3 (int data1, char data2, int data3);
   void function4 (int arg1, int arg2);

   The "function3" is having the different signature than the functions "function1" and "function2" as it differs in the number of arguments accepted.  Even though "function4" is accepting two arguments, it is having different signature than the "function1" and "function2" as its 2nd argument type differs.


Why does the Signature of a function matter?
    A function pointer always points to a function with a specific signature. So, we cannot use the same function pointer to point functions with two different signatures.
    For normal pointers, using typecast we can store address of variable of one particular type into a pointer of different type. Consider the below case.

   int *ptr = NULL;
   char data='v';
   ptr = (int*)&data;

  In the above example, we are storing the address of character variable into integer pointer using typecast. But this is NOT possible with function pointers which makes it unique and different.

Function Pointer Declaration:
    The function pointer can be declared as given below.
     <return-type> (*FnPtrName) (<argtype arg1>, <argtype arg2>,....<argtyp argN>)
                                          or
     <return-type> (*FnPtrName) (void)

  In the above syntax, the return-type can be void or any valid return types. FnPtrName can be any variable name which will be used for accessing the function pointers. It can accepts any number of arguments or it can be void.

Example:
  int (*FunPtr) (int,int) = NULL;
  
  In the above example, the function pointer is named as "FunPtr" and it accepts two integers as arguments and returns integer value. This pointer is initialized to NULL during definition of that variable.
  This function pointer can be used to store the address of any functions which is matching the signature of this function pointer; i.e any functions which is accepting two integer arguments and  returns integer results.

 
 Assigning an address to a Function pointer:

    Consider the below two function prototypes.
    int add (int,int);
    int sub (int,int);


    The functions "add" and "sub" accepts two integer arguments and returns integer results. These functions having the same signature as that of the function pointer defined in the previous example. So, we can manipulate these functions using the function pointer in example.
   We can assign the address of a function to a function pointer in two ways.

    FunPtr = add; (or) FunPtr = &add;

   Both of the above initialization are valid. The starting address of those functions will be assigned to the function pointer.

Comparing Function Pointers:
    We can compare a value of the function pointer using "==" operator as given below.

     if ((FunPtr == add) ||(*FunPtr == add))   /* We can compare directly specifying the function pointer or we can compare by de-referencing the function pointer ; both are same */
        printf ("Function Pointer Pointing to add function\n");
     else if ((FunPtr == &sub) || (*FunPtr == &sub))
       printf ("Function Pointer Pointing to sub function\n");

   When we specify "add" or "&sub", the starting address of those functions  are compared with the function pointers.

Invoking Function using a function pointer:
    We can call a function using function pointer in two ways. We can directly use the name of the function pointer or we can de-reference that function pointer.

    rslt = FunPtr (10,20); (or) rslt = (*FunPtr) (10,20);


Example:
    In this example we will put together the concepts introduced above.

 #include <stdio.h>
int add (int,int);
int sub (int,int);
int main()
{
    int var1 = 10, var2 = 20, rslt = 0;

    int (*FunPtr) (int,int) = NULL;

    FunPtr = &add;

    rslt = FunPtr (var1,var2);    /* Calling function "add" using function pointer */
    printf ("Addition Result:%d\r\n",rslt);



    if (FunPtr == add)   /* Comparing Function pointer and function */
    {
        printf ("Function Pointer is pointing to add Function\n");
    }
    else if (FunPtr == sub)
    {
        printf ("Function Pointer is pointing to sub Function\n");
    }

    FunPtr = sub;  /* Now, the function  pointer pointing to "sub"; it is possible as "sub" has the same function signature as "add" */

    rslt = (*FunPtr) (var1,var2); /* Calling "sub" by de-referencing the function pointer */
    printf ("Subtraction Result:%d\r\n",rslt);

    if (FunPtr == &add)
    {
        printf ("Function Pointer is pointing to add Function\n");
    }
    else if (*FunPtr == &sub)
    {
        printf ("Function Pointer is pointing to sub Function\n");
    }

    return 0;
}

int add (int val1, int val2)
{
    return (val1+val2);
}

int sub (int val1, int val2)
{
    return (val1-val2);
}

Output:

Addition Result:30
Function Pointer is pointing to add Function
Subtraction Result:-10
Function Pointer is pointing to sub Function
  

No comments:

Post a Comment