Guide to Function Pointer in C\C++

Home / Guide to Function Pointer in C\C++

Guide to Function Pointer in C\C++

November 24, 2015 | Article | No Comments

A function pointer is a variable that stores the address of a function that can later be called through that function pointer. This concept is interesting and really useful because functions encapsulate behavior. For instance, every time you need a particular behavior such as drawing a line, instead of writing out a bunch of code, all you need to do is call the function. But sometimes you would like to choose different behaviors at different times in essentially the same piece of code. Read on for concrete examples.

Function pointer is a pointer, however they are less error prone than normal pointers cause you will never allocate or deallocate memory with them. But keep in mind: do it if must, ask yourself if you need a function pointer. Also you have to remember that a running program gets a certain space in memory.

Example Uses of Function Pointers

(1) Functions as Arguments to Other Functions

If you were to write a sort routine, you might want to allow the function’s caller to choose the order in which the data is sorted; some programmers might need to sort the data in ascending order, others might prefer descending order while still others may want something similar to but not quite like one of those choices. One way to let your user specify what to do is to provide a flag as an argument to the function, but this is inflexible; the sort function allows only a fixed set of comparison types (e.g., ascending and descending).

A much nicer way of allowing the user to choose how to sort the data is simply to let the user pass in a function to the sort function. This function might take two pieces of data and perform a comparison on them. Well, if you are familiar with STL especially in <algorithm> you may have met one before.

(2) Callback Functions

Another use for function pointers is setting up “listener” or “callback” functions that are invoked when a particular event happens. The function is called, and this notifies your code that something of interest has taken place.

Why would you ever write code with callback functions? You often see it when writing code using someone’s library. One example is when you’re writing code for a graphical user interface (GUI). Most of the time, the user will interact with a loop that allows the mouse pointer to move and that redraws the interface. Sometimes, however, the user will click on a button or enter text into a field. These operations are “events” that may require a response that your program needs to handle. How can your code know what’s happening? Using Callback functions! The user’s click should cause the interface to call a function that you wrote to handle the event.

A win32 programmer especially who build application from scratch with Win32 API would met at least one callback function. This function is the function called everytime a message is translated and dispatch from main loop.

To get a sense for when you might do this, consider what might happen if you were using a GUI library that had a “create_button” function. It might take the location where a button should appear on the screen, the text of the button, and a function to call when the button is clicked. Assuming for the moment that C (and C++) had a generic “function pointer” type called function, this might look like this:

void create_button( int x, int y, const char *text, function callback_func );

Whenever the button is clicked, callback_func will be invoked. Exactly what callback_func does depends on the button; this is why allowing the create_button function to take a function pointer is useful.

Learn the Basic

(1) Function Pointer Syntax

The syntax for declaring a function pointer might seem messy at first, but in most cases it’s really quite straight-forward once you understand the concept.Also, there are two different types of function pointers: one is for ordinary C\C++ functions or to static C++ member, other is pointer to non-static C++ member function. The basic difference is that all pointers to non-static member function need a hidden argument. Also remember that these two types of function pointers are incompatible with each other.

Let’s look make some example. We create function pointers with one argument and return an integer.

/* Define a function pointer and initialize to NULL or nullptr in C++11 */
int (*ptr2Function)(int) = NULL;
int (TMyClass::*ptr2Member)(int) = NULL;
int (TMyClass::*ptr2ConstMember)(int) const = NULL;

Now we have three function pointers: ptr2Function, ptr2Member, and ptr2ConstMember. The ptr2Function is a normal function pointer, ptr2Member is function pointer which is a member of a class TMyClass, while ptr2ConstMember is similar with ptr2Member but it is a const function.

The key to writing the declaration for a function pointer is that you’re just writing out the declaration of a function but with (*func_name) where you’d normally just put func_name.

(2) Reading Function Pointer Declarations

Sometimes people get confused when more stars are involved:

void *(*func)(int *);

Here, the key is to read inside-out. Notice that the innermost element of the expression is *func, and that otherwise it looks like a normal function declaration. *func should refer to a function that returns a void * and takes an int *. Consequently, foo is a pointer to just such a function.

(3) Assigning Function Pointers

It’s quite easy to assign a function pointer. Remember that function pointers are basically a pointer thus you should feed it with an address. In specific, we need to assign it with an address of a function in our program. The syntax is like any other variable:

/* We have these functions */
int DoOne (int a) { printf("DoOne\n"); return a+135; }
int DoTwo (int a) { printf("DoTwo\n"); return a+182; }

/* This is how we assign them */
ptr2Function = DoOne;  // short form
ptr2Function = &DoTwo; // correct assignment using address operator

/* As for classes */
class TMyClass
{
public:
    int DoOne(int a) { cout << "TMyClass::DoOne" << endl; return a+135; }
    int DoTwo(int a) const { cout << "TMyClass::DoTwo" << endl; return a+182; }

/* more of TMyClass */
};

/* and this is how we assign them */
ptr2ConstMember = &TMyClass::DoTwo; // correct assignment using address operator
ptr2Member = &TMyClass::DoOne; // note: <ptr2Member> may also legally point to &DoTwo

(4) Using a Function Pointer

To call the function pointed to by a function pointer, we treat the function pointer as though it were the name of the function we wish to call.We dereferencing it using the * operator. Alternatively, we may also just use the function pointer’s instead of the function’s name. In C++ the two operator .* and ->* are used together with an instance of a class in order to call one of their (non-static) member functions. If the call takes place within another member function you may use the “this”-pointer.

int result1 = ptr2Function (30);  // short way
int result2 = (*ptrFunction)(30); // dereference it

TMyClass instance1;
int result3 = (instance1.*ptr2Member)(30);
int result4 = (*this.*ptr2Member)(30);      // if this-pointer can be used

TMyClass* instance2 = new TMyClass;
int result5 = (instance2->*ptr2Member)(30);
delete instance2;

See how flexible it is with or without *. At least you specify the function name.

(5) Passing a Function Pointer as Argument

We can pass a function pointer as a function’s calling argument. Let’s see how we can do this:

/* ptr2Func is a pointer which returns an int and takes an int */
void PassMe (int (*ptr2Func) (int))
{
    int result = (*ptr2Func)(30);  // call using function pointer
    cout << result << endl;
}

/* Now we execute it */
void Pass_a_Function_Pointer()
{
    PassMe(&DoOne);
}

Next, let’s remember one example before, the sorting. We mentioned function pointer to write a generic sorting routine where the exact order could be specified by programmer calling the sorting function. It turns out that the C function qsort does just that.

From the Linux man pages, we have the following declaration for qsort (from stdlib.h):

void qsort(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *));

Note the use of void*s to allow qsort to operate on any kind of data (in C++, you’d normally use templates for this task, but C++ also allows the use of void* pointers) because void* pointers can point to anything. Because we don’t know the size of the individual elements in a void* array, we must give qsort the number of elements, nmemb, of the array to be sorted, base, in addition to the standard requirement of giving the length, size, of the input.

But what we’re really interested in is the compar argument to qsort: it’s a function pointer that takes two void *s and returns an int. This allows anyone to specify how to sort the elements of the array base without having to write a specialized sorting algorithm. Note, also, that compar returns an int; the function pointed to should return -1 if the first argument is less than the second, 0 if they are equal, or 1 if the second is less than the first.

For instance, to sort an array of numbers in ascending order, we could write code like this:

#include <stdlib.h>

int int_sorter( const void *first_arg, const void *second_arg )
{
    int first = *(int*)first_arg;
    int second = *(int*)second_arg;
    if ( first < second )
    {
        return -1;
    }
    else if ( first == second )
    {
        return 0;
    }
    else
    {
        return 1;
    }
}

int main()
{
    int array[10];
    int i;
    /* fill array */
    for ( i = 0; i < 10; ++i )
    {
        array[ i ] = 10 - i;
    }
    qsort( array, 10 , sizeof( int ), &int_sorter );
    for ( i = 0; i < 10; ++i )
    {
        printf ( "%d\n" ,array[ i ] );
    }

}

(6) Returning a Function Pointer

It’s a little bit tricky but a function pointer can be a function’s return value. Just watch the grammar, the syntax should be correct to ensure we are on the right track.

There are two solutions of how to return a pointer to a function which is taking two float arguments and returns a float. If you want to return a pointer to a member function you have just got to change the definitions/declarations of all function pointers.

/* The function which we return */
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; }

/*
   Direct solution: Function takes a char and returns a pointer to a function
   which is taking two floats and returns a float. <opCode> specifies which
   function to return
*/
float (*GetPtr1(const char opCode))(float, float)
{
    switch (opCode) {
        case '+': return &Plus;
        case '-': return &Minus;
        case '*': return &Multiply;
        case '/': return &Divide;
    }
}

/*
   Solution using a typedef: Define a pointer to a function which is taking
   two floats and returns a float
*/
typedef float(*TPtr2Func)(float, float);

TPtr2Func GetPtr2(const char opCode)
{
    switch (opCode) {
        case '+': return &Plus;
        case '-': return &Minus;
        case '*': return &Multiply;
        case '/': return &Divide;
    }
}

/* Invocation */
int main() {
    float (*ptr2Function)(float, float) = NULL;

    ptr2Function = GetPtr1('+');
    cout << (*ptr2Function)(135, 182) << endl;

    ptr2Function = GetPtr2('-');
    cout << (*ptr2Function)(135, 182) << endl;

    // we can also call it directly
    cout << GetPtr1('*')(135, 182) << endl;
    cout << GetPtr2('/')(135, 182) << endl;
}

(7) Array of Function Pointers

Operating with arrays of function pointers is very interesting. This offers the possibility to select a function using an index. The syntax appears difficult, which frequently leads to confusion. Below you find two ways of how to define and use an array of function pointers: The first way uses a typedef, the second way directly defines the array.

Here’s the procedural way:

/*
  typedef-definition: <TPtr2Function> now can be used as a type 
*/
typedef int (*TPtr2Function)(int);

void illustration() {
    /* Create arrays and initialize with NULL. <funcArr1> and <funcArr2> are arrays with 10 pointers to functions which returns an int and take an int */

    /* 1st way, using TPtr2Function */
    TPtr2Function funcArr1[10] = {NULL};

    /* 2nd way, directly defining the array */
    int (*funcArr2[10])(int) = {NULL};

    /* Assign the function address - 'DoOne' and 'DoTwo' are suitable functions */
    funcArr1[0] = funcArr2[0] = &DoOne;
    funcArr1[1] = funcArr2[1] = &DoTwo;

    /* Calling DoOne */
    funcArr1[0](30);
    funcArr2[0](30);

    /* Calling DoTwo */
    funcArr1[1](30);
    funcArr2[1](30);
}

And if we have class:

typedef int (TMyClass::*TPtr2Member)(int);

void illustration() {
    /* Create arrays and initialize with NULL. <funcArr1> and <funcArr2> are arrays with 10 pointers to functions which returns an int and take an int */

    /* 1st way, using TPtr2Member */
    TPtr2Member funcArr1[10] = {NULL};

    /* 2nd way, directly defining the array */
    int (TMyClass::*funcArr2[10])(int) = {NULL};

    /* Assign the function address - 'DoOne' and 'DoTwo' are suitable functions */
    funcArr1[0] = funcArr2[0] = &TMyClass::DoOne;
    funcArr1[1] = funcArr2[1] = &TMyClass::DoTwo;

    TMyClass instance;

    /* Calling DoOne */
    instance.*funcArr1[0](30);
    instance.*funcArr2[0](30);

    /* Calling DoTwo */
    instance.*funcArr1[1](30);
    instance.*funcArr2[1](30);
}

Comparing Function Pointers

We can use the comparison operators (==, !=) the same way as usual.

if (ptr2Function > 0) {
    if (ptr2Function == &DoOne) {
        printf("Pointer points to DoOne");
    }
} else {
    printf("Pointer not initialized!!);
}

// -----

if (ptr2ConstMember == &MyClass::DoTwo) {
    cout << "Pointer points to TMyClass::DoTwo" << endl;
}

Using Polymorphism and Virtual Functions Instead of Function Pointers

You can often avoid the need for explicit function pointers by using virtual functions. For instance, you could write a sorting routine that takes a pointer to a class that provides a virtual function called compare:

class Sorter
{
    public:
    virtual int compare (const void *first, const void *second);
};

// cpp_qsort, a qsort using C++ features like virtual functions
void cpp_qsort(void *base, size_t nmemb, size_t size, Sorter *compar);

inside cpp_qsort, whenever a comparison is needed, compar->compare should be called. For classes that override this virtual function, the sort routine will get the new behavior of that function. For instance:

class AscendSorter : public Sorter
{

    virtual int compare (const void*, const void*)
    {
        int first = *(int*)first_arg;
        int second = *(int*)second_arg;
        if ( first < second ) {
            return -1;
        } else if ( first == second ) {
            return 0;
        } else {
            return 1;
        }
    }
};

and then you could pass in a pointer to an instance of the AscendSorter to cpp_qsort to sort integers in ascending order.

But Are You Really Not Using Function Pointers?

Virtual functions are implemented behind the scenes using function pointers, so you really are using function pointers–it just happens that the compiler makes the work easier for you. Using polymorphism can be an appropriate strategy (for instance, it’s used by Java), but it does lead to the overhead of having to create an object rather than simply pass in a function pointer.

,

About Author

about author

xathrya

A man who is obsessed to low level technology.

Leave a Reply

Your email address will not be published. Required fields are marked *

Social media & sharing icons powered by UltimatelySocial