Wednesday

Function pointer


Function Pointers

Function Pointers: A function pointer is a variable which is used to hold the starting address of a functions and the same can be used to invoke a function. It is also possible to pass address of different functions at different times thus making the function more flexible and abstract. 

So the function pointers can be used to simplify code by providing a simple way to select a function to execute based on run-time values. Function pointers do always point to a function having a specific signature. Thus, all functions used with the same function pointer must have the same parameters and return type.

 Let us illustrate this concept through a C program as follows (Listing-1: p1.c):
/* p1.c */
#include <stdio.h>
void f()
{
printf("In f().\n");
}
int main()
{
printf("Code corresponding to f() is stored at: %p\n", f);
return 0;
}
(Listing-1: p1.c)
Note: Here we are using “%p” as a special format specifier in “printf” function to print the address of a location. It prints the input argument as a pointer.
This program prints the starting address of location where the code corresponding to function “f( )” is stored. For this instance it is 0291 (Output-1), but it may vary for different compilers and for different operating systems.

A function’s name actually represents a pointer which we use to call that function. So in reality whenever we call a function we are calling it through a pointer only. Let us consider the code snippet in Listing-2 to illustrate this point.
/* p2.c */
#include <stdio.h>
void f()
{
printf("In f().\n");
}
int main()
{
f();
      return 0;
}
(Listing-2: p2.c)
The Output-2 shows the runtime behavior of “p2.exe”.

Even though the first statement in “main” function actually uses a pointer it is not obvious enough to believe it. To enforce our understanding now let us create a pointer variable suitable to store the starting address of function “f( )”. As we create a pointer variable for a given data type, we create a function pointer according to the function type. The function type is defined by:
  1. Return type of a function
  2. Number of arguments to the function
  3. Types of these arguments to the function

You obtain the address of a function by using the function’s name without any parentheses or arguments. This is similar the way an array’s address is obtained when only the array name, without indexes, is used. Once a pointer points to a function, the function can be called through that pointer. Considering this we can create a function pointer “ptr” to function “void f( )” as “void (*ptr)( );”. Listing-3 illustrates the use of this function pointer as follows: 


/* p3.c */
#include <stdio.h>
void f()
{
printf("In f().\n");
}
int main()
{
void (*ptr)();
ptr=f;
ptr();
      return 0;
}

(Listing-3: p3.c)
In Listing-3, the first line in “main” function creates the required function pointer “ptr”. In the second line the starting address of function “f( )” is stored in “ptr” through a simple assignment. This proves that the name of a function is nothing but a pointer. In third line the pointer variable “ptr” is used to call the function whose starting address is stored in it. In this case it happens to be function “f( )”. Output-3 shows the runtime behavior of “p3.exe” which is exactly same as that of “p2.exe”.


Now let us consider another example to reinforce our understanding of function pointers. Let us create a function “add” which will take two integer arguments and returns an integer value as a result of the addition. We will also create a function pointer “ptr” corresponding to the required function type. Then we will assign the address of function “add” to function-pointer “ptr”. Then onwards “ptr” can be used as a replacement for “add” whenever required. Listing-4 represents the corresponding C program as follows:  


/* p4.c */
#include <stdio.h>
int add(int a, int b)
{
return a+b;
}
int main()
{
int c;
int (*ptr)(int, int);
      ptr=add;
c=ptr(2, 8);
printf("%d", c);
      return 0;
}

(Listing-4: p4.c)
The Output-4 shows the runtime behavior of “p4.exe”. It clearly demonstrates the interchangeability between calling a function through its name or through a corresponding function pointer.






2: Applications of Pointers to Functions
You may wonder about the usefulness of this approach. Why to call a function through a function pointer rather than simply through its name? Answer to this question is hidden in the power of pointer usage. A function pointer should be considered just as a variable which stores an address. Therefore most of the characteristics applicable to normal pointers are also available for function pointers.


2.1: Refer Multiple Functions through the Same Function Pointer

A pointer refers to different entities depending upon whose address is stored in it. This advantage of pointers is available to the function pointers also. Thus we can call different functions using the same function pointer variable. The only restriction is that all of those functions must follow the same function type. Let us consider a C program (Listing-5: p5.c) to illustrates this flexibility of a function pointer.  


/* p5.c */
#include <stdio.h>
void f1()
{
printf("In f1().\n");
}
void f2()
{
printf("In f2().\n");
}
int main()
{
void (*ptr)();
      ptr=f1;
ptr();
      ptr=f2;
ptr();
      return 0;
}


(Listing-5: p5.c)
The Output-5 describes the runtime behavior of “p5.exe”. This supports our understanding that a function pointer can be used to call different functions by assigning their respective addresses to it.

2.2: Pass Functions as Arguments to Other Functions
Function pointers also allow functions to be passed as arguments to other functions. Function pointers allow us to handle functions as if they are variables. This allows us to pass functions themselves as arguments to other functions using function pointer arguments. Let us illustrate this point through an example (Listing-6: p6.c).  


/* p6.c */
#include <stdio.h>
void f1()
{
printf("In f1().\n");
}
void f2()
{
printf("In f2().\n");
}
void msg(int nCnt, void (*ptr)())
{
int i;
for(i=0; i<nCnt; i++) ptr();
}
int main()
{
msg(3, f1);
msg(2, f2);
      return 0;
}


(Listing-6: p6.c)
Output-6 shows the output of the above program. It is self explanatory enough to illustrate the use of function pointers as an argument passing mechanism.

Note: Many of the standard C library functions require functions to be passed as arguments.
e.g. “qsort( )” function sorts the data using Quick Sort algorithm.
void qsort(void *base, size_t nelem, size_t width, int (*fcmp)(const void *, const void *));
It accepts a comparator function to be passed as an argument. It declares its type as:
int sort_function( const void *a, const void *b);

2.3: Array of Functions
One of the fascinating things one can do through function pointers is to create an array of functions. Once in place we can access this array as if we are accessing any other array through an integer index. Listing-7 exhibits a corresponding example which first creates an array of five functions and then uses them through a loop.
/* p7.c */
#include <stdio.h>
void f1() { printf("In f1().\n"); }
void f2() { printf("In f2().\n"); }
void f3() { printf("In f3().\n"); }
void f4() { printf("In f4().\n"); }
void f5() { printf("In f5().\n"); }
int main()
{
int i;
      void (*ptrArr[])() = { f1, f2, f3, f4, f5 };
      for(i=0; i<5; i++) ptrArr[i]();
      return 0;
}

(Listing-7: p7.c)
The output of “p7.exe” is shown in Output-7. It describes the way we accessed functions f1, f2, f3, f4 and f5 through an array using an integer index.

You may wonder why anyone would write a program this way. Obviously in the simple programs illustrated in this article, nothing is gained significantly and sometimes confusion may also be introduced unnecessarily. However, at times it is advantageous to pass functions as parameters or to create an array of functions. For example, when a compiler or interpreter is written, the parser often calls various support functions, such as those that compute mathematical operations, perform I/O, or access system resources. Instead of having a large “switch-case” construct with all these functions listed in, an array of function pointers can be created. In this approach, the proper function is selected by its index.

3: Idiosyncrasies Involved in the Usage of Pointers to Functions

Usage of pointers to functions may become confusing due to some idiosyncrasies involved. The confusing usage of “*” gives rise to them. Listing-8 illustrates this issue with a C program. This program will compile and run properly without any syntax or runtime errors. Especially have a look at the various ways been used to call function “f ( )” through function pointer “ptr”.
/* p8.c */
#include <stdio.h>
void f() { printf("In f().\n"); }
int main()
{
void (*ptr)();
ptr=f;
      ptr();
(ptr)();
(*ptr)();
(**ptr)();
(***ptr)();
(****ptr)();
(*****ptr)();
      return 0;
}
(Listing-8: p8.c)
Output-8 shows that the “p8.exe” executed without any runtime error. The output of each method to call function “f( )” through “ptr” is identical with each other. Notice that how the pointer “*” can be added or dropped at will without any effect on the final output. This quirk in C is due to the way it handles the function pointers: calls to a function and calls to a function through a pointer (or any level of pointer indirection) can use the same syntax. We can simplify this confusion by consistently using function pointers the way we use normal functions.


Kindly Bookmark this Post using your favorite Bookmarking service:
Technorati Digg This Stumble Stumble Facebook Twitter
YOUR ADSENSE CODE GOES HERE

0 comments:

Post a Comment

Dont Forget for Commets

 

| C programing tutorials © 2009. All Rights Reserved | Template Style by My Blogger Tricks .com | Design by Brian Gardner | Back To Top |