Function Pointers


Simple Explanation

What is a Function Pointer?

Function Pointers are pointers, i.e. variables, which point to the address of a function. You must keep in mind, that a running program gets a certain space in the main-memory. Both, the executable compiled program code and the used variables, are put inside this memory. Thus a function in the program code is, like e.g. a character field, nothing else than an address. It is only important how you, or better your compiler/processor, interpret the memory a pointer points to

 Introductory Example or How to Replace a Switch-Statement

When you want to call a function DoIt() at a certain point called label in your program, you just put the call of the function DoIt() at the point label in your source code. Then you compile your code and every time your program comes up to the point label, your function is called. Everything is ok. But what can you do, if you don’t know at build-time which function has got to be called? What do you do, when you want to decide it at runtime? Maybe you want to use a so called Callback-Function or you want to select one function out of a pool of possible functions. However you can also solve the latter problem using a switch-statement, where you call the functions just like you want it, in the different branches. But there’s still another way: Use a function pointer!

In the following example we regard the task to perform one of the four basic arithmetic operations. The task is first solved using a switch-statement. Then it is shown, how the same can be done using a function pointer. It’s only an example and the task is so easy that I suppose nobody will ever use a function pointer for it 😉

//————————————————————————————
// 1.2 Introductory Example or How to Replace a Switch-Statement
// Task: Perform one of the four basic arithmetic operations specified by the
//       characters ‘+’, ‘-‘, ‘*’ or ‘/’.

// The four arithmetic operations … one of these functions is selected
// at runtime with a swicth or a function pointer

float Plus    (float a, float b) { return a+b; }
float Minus   (float a, float b) { return a-b; }
float Multiply(float a, float b) { return a*b; }
float Divide  (float a, float b) { return a/b; }

// Solution with a switch-statement – <opCode> specifies which operation to execute
void Switch(float a, float b, char opCode)
{
   float result;

   // execute operation
   switch(opCode)
   {
      case ‘+’ : result = Plus     (a, b); break;
      case ‘-‘ : result = Minus    (a, b); break;
      case ‘*’ : result = Multiply (a, b); break;
      case ‘/’ : result = Divide   (a, b); break;
   }

   cout << “Switch: 2+5=” << result << endl;         // display result
}

// Solution with a function pointer – <pt2Func> is a function pointer and points to
// a function which takes two floats and returns a float. The function pointer
// “specifies” which operation shall be executed.

void Switch_With_Function_Pointer(float a, float b, float (*pt2Func)(float, float))
{
   float result = pt2Func(a, b);    // call using function pointer

   cout << “Switch replaced by function pointer: 2-5=”// display result
   cout << result << endl;
}

// Execute example code
void Replace_A_Switch()
{
   cout << endl << “Executing function ‘Replace_A_Switch'” << endl;

   Switch(2, 5, /* ‘+’ specifies function ‘Plus’ to be executed */ ‘+’);
   Switch_With_Function_Pointer(2, 5, /* pointer to function ‘Minus’ */ &Minus);
}

Important note: A function pointer always points to a function with a specific signature! Thus all functions, you want to use with the same function pointer, must have the same parameters and return-type!

  

In Depth Explantion

What are function pointers?

 Function pointers are means to add another level of indirection. Remember pointers to variables? Function pointers are no different.

Let’s say that there are two identical functions a and b (by identical we mean that the functions have the same return type and the same parameter type). We also declare a function pointer p. The function pointer is defined such that it shares the same return type and parameter types as a and b. By assigning the address of a to p, p = a;, calls to p will in effect yield calls to a. Likewise, p can be assigned b, where calls to p yield calls to b. Getting dizzy yet? 😉

Here’s a very simple example which works with C and C++.

#include <stdio.h>

void a(void)
{
   printf(“a was called.\n”);
}

void b(void)
{
   printf(“b was called.\n”);
}

int main(void)
{
   void (*p)(void); /* This is a function pointer declaration */

   p = a;
   (*p)();          /* Using function pointer p               */
   p = b;
   (*p)();          /* Using function pointer p (again)       */
   return 0;        /* Standard exit procedure in UNIX        */
}
 
As you can see, the function pointer declaration looks somewhat complicated. The “standard remedy” for this is to create a new function pointer type by using the typedef operator.

Same example again using the typedef operator.

#include <stdio.h>

typedef void (*FuncType)(void); /* FuncType is a function pointer type */

void a(void)
{
   printf(“a was called.\n”);
}

void b(void)
{
   printf(“b was called.\n”);
}

int main(void)
{
   FuncType p;      /* This is a function pointer declaration */

   p = a;
   (*p)();          /* Using function pointer p               */
   p = b;
   (*p)();          /* Using function pointer p (again)       */
   return 0;        /* Standard exit procedure in UNIX        */
}
 
What advantage does this give me?

As you probably learned in your first programming courses, pointers to variables allows you to modify variable contents from a non-local environment. This gives the flexibility of writing generic functions which do not alter “known” global variables, but references to “unknown” variables. Such functions can be reused. Function pointers gives you the same flexibility, but at a higher level. Instead of calling a “known” function, one can call any arbitrary “unknown” function. This is the main advantage of function pointers: greater flexibility and better code reuse.

Example – Iterating through a list

In this example I’ll show a very common (and naive) solution for iterating through a list, then a somewhat “better” solution and last I’ll show a general and resuable solution.

The list is a list of strings and we want to iterate it for printing to screen. As a twist, we also want to print out the a list of the string lengths rather than the strings.

Example 1 – Code:
This is a very naive implementation.

#include <stdio.h>

typedef struct ListRecord List;

struct ListRecord {
   char*       text;
   List*       next;
};

List* listInsert(List* list, const char* text)
{
   ListRecord* rec;

   rec = (ListRecord*)malloc(sizeof(ListRecord));
   rec->text = strdup(text); /* Make a copy of string */
   rec->next = list;         /* Link in old list */
   return list;
}

int main(void)
{
   List* list;
   ListRecord* i;

   list = NULL;
   list = listInsert(list, “World!”);
   list = listInsert(list, “Hello”);

   printf(“List begins\n”);
   for(i = list; i != NULL; i = i->next)
      printf(“Text: %s\n”, i->text);      
   printf(“List ends\n”);

   printf(“List begins (lengths)\n”);
   for(i = list; i != NULL; i = i->next)
      printf(“Text Length: %d\n”, strlen(i->text));
   printf(“List ends\n”);

   return 0;
}
 
Example 2 – Code:
This is a better implementation. Functionality has been moved out into separate functions. printList and printListStrLen are new functions.

#include <stdio.h>

typedef struct ListRecord List;

struct ListRecord {
   char*       text;
   List*       next;
};

void printList(List* list)
{
   ListRecord* i;

   printf(“List begins\n”);
   for(i = list; i != NULL; i = i->next)
      printf(“Text: %s\n”, i->text);      
   printf(“List ends\n”);
}

void printListStrLen(List* list)
{
   ListRecord* i;

   printf(“List begins (reversed)\n”);
   for(i = list; i != NULL; i = i->next)
      printf(“Text Length: %s\n”, strlen(i->text));
   printf(“List ends\n”);
}

List* listInsert(List* list, const char* text)
{
   ListRecord* rec;

   rec = (ListRecord*)malloc(sizeof(ListRecord));
   rec->text = strdup(text); /* Make a copy of string */
   rec->next = list;         /* Link in old list */
   return list;
}

int main(void)
{
   List* list;

   list = NULL;
   list = listInsert(list, “World!”);
   list = listInsert(list, “Hello”);

   printList(list);
   printListStrLen(list);
  
   return 0;
}
 
Example 3 – Code:
This solution is the best of the three since it allows for high code reuse. It makes use of function pointers for performing the actual printing and it separates the “for-looping” into a function of its own. The three new key features in this example is ListRecordOperation, print, printStrLen and listForEach. Note that adding new features such as printing the text in reverse is now very easy. Just add a function that is compatible with the ListRecordOperation type and call listForEach with the function as argument. No more tedious moments of writing for-loops and such, now you can focus on the problem at hand instead.

#include <stdio.h>

typedef void (*ListRecordOperation)(const char*);

typedef struct ListRecord List;

struct ListRecord {
   char*       text;
   List*       next;
};

/* function compatible with ListRecordOperation */
void print(const char* text)
{
   printf(“Text: %s\n”, text);      
}

/* function compatible with ListRecordOperation */
void printStrLen(const char* text)
{
   printf(“Text Length: %s\n”, strlen(text));
}

void listForEach(List* list, ListRecordOperation op)
{
   ListRecord* i;

   for(i = list; i != NULL; i = i->next)
      (*op)(list->text); /* Calling whatever op points to with i->text
                            as argument */
}

List* listInsert(List* list, const char* text)
{
   ListRecord* rec;

   rec = (ListRecord*)malloc(sizeof(ListRecord));
   rec->text = strdup(text); /* Make a copy of string */
   rec->next = list;         /* Link in old list */
   return list;
}

int main(void)
{
   List* list;

   list = NULL;
   list = listInsert(list, “World!”);
   list = listInsert(list, “Hello”);

   listForEach(list, print);
   listForEach(list, printStrLen);

   return 0;
}
 
Useful tips for programmers
Short hand notation
Function pointers may be used with a shorthand notation. Instead of dereferencing the function pointer with an asterisk:

p = a;
(*p)();
    
you can use it like this:

p = a;
p();
    
as if it was an “ordinary” function. Gives C an aesthetic appeal. 😉

Module abstraction and indepenence
During the development phase of a project, the code is more or less always in a state of flux. Often, one wants to change the interface of some module so that it can serve some other modules needs better. Communication between modules may very well be done using function pointers. A prime example of this is the frontend.cpp and menu.cpp modules in the lab files (dsa-lab.tar). In fact this is the only way that the menu subsystem can call functions in the frontend module without having “intimate” knowledge them.

The code which creates the menu items looks like this:

listMenu->add(new MenuItem(‘a’, “Append data”, Handler_app)); 

 

 

One response to “Function Pointers

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s