Sign in to follow this  
Gink

Function Pointers?

Recommended Posts

I dont understand function pointers, what are they used for?? Can anyone show how you would use one? They basically call another function??I dont see any practical use for that.

Share this post


Link to post
Share on other sites
C++ virtual functions are basically implemented by injecting a pointer to a table of function pointers in every object of a class that has virtual functions. At run-time, the system relies on these pointers to figure out which version of the function it is supposed to call.

If you were building a text-based RPG, you would want to associate each command the user can type with a function. The easiest way to do that is to have a table of string/function pointer pairs.

You can store a function pointer with the data associated with a button in a GUI to determine the function that gets called when the button is pressed. You can dynamically change that association by assigning a different function pointer to the button.

More generally you can cause a function to be called when an event occurs, and change the event/function pairings at your whim.

Share this post


Link to post
Share on other sites
Quote:
Original post by Gink
You cant do that by just calling the function?


But if you "just call the function", you have to tell the computer, right there in your code, which function you want to call. Using function pointers, this information can be treated as data. You can store it, change it ... until you actually use it and call the function.

The code that uses the function pointer doesn't need to know precisely which function it is calling. In Win32 programming, you often provide the system which callback functions: pointer to functions you want the system to call in such and such circumstances. The Win32 framework doesn't actually know what functions you're going to provide it with; it only knows their signatures (parameters and return type), so that it can actually call them, but that's it.

Share this post


Link to post
Share on other sites
Use #1: Callbacks.

Suppose I design a container class that implements some type of sorting functionality. But, I want the user of my class to be able to specify how items in my container are to be sorted by specifying their own comparison function.
The STL containers use this all over the place. Another example would be the qsort function.

There are a number of other uses for callbacks, like event notifications and such, but you get the idea.


Use #2: Run-time logic

This probably isn't a good example, but it's the first one that popped into my head. You could create a mapping between a command and an action.
Something like this: (note that I just winged this.. I havn't used function pointers for a while, so the syntax may not be 100% correct.. here's a good reference though)

typedef void (*ActionFunction)();
std::map<std::string, ActionFunction> mapActions;

// add actions to our map
mapActions["hit"] = myHitFunction;
mapActions["give"] = myGiveFunction;
mapActions["run"] = myRunFunction;

/*
... elsewhere
*/

// call the "hit" method.
mapActions["hit"]();







Yes, you could do this with a bunch of chained "if-else if" statements, but this method is cleaner, and potentially faster if you have a LOT of possible actions.


Edit: Possible Use #3:
Just had this thought.. you could create an array/vector/dequeue/whatever of function pointers to implement a rudimentary call stack.

Share this post


Link to post
Share on other sites
Basic example, as I've not seen it directly covered in this post (although pragma Fury covers more complex examples and stuff :-))

#include <iostream>
using namespace std;

void foo ( void ) {
cout << "foo" << endl;
}

void bar ( void ) {
cout << "bar" << endl;
}

int main ( void ) {
void (*foo_or_bar)( void );

foo_or_bar = foo;
foo_or_bar(); //prints "foo"

foo_or_bar = bar;
foo_or_bar(); //prints "bar"
}


Share this post


Link to post
Share on other sites
Pragma Fury, I don't know what you were planning to do with your second implementation, but I do know that that mapping of strings to functions is the basis of my console at least, and if I didn't have function pointers, I'd be stuck with a lot of repetative, ugly code.

Share this post


Link to post
Share on other sites
Quote:
Original post by Gink
So they are used for convenience and not because they are needed?


In many cases they are needed. Without them, the C library function qsort, mentioned by pragma Fury would be impossible. Since the function lives in a library, you cannot modify it to call whichever comparison operations is correct for your code (you don't compare ints and strings the same way). So there would have to be one such function for each type of entity to compare. And if you were to come up with your own type, an array of which you want to sort, you would be out of luck and would have to rewrite the sorting function yourself.

A function pointer allows you to tell qsort which comparison function is to be used. The qsort function itself doesn't know anything about how your comparison works (in fact, it knows precious little about what you're passing it), and just uses it as a black box in its quicksort algorithm.

With a function pointer, you can call "the function stored in the pointer" without explicitely specifying (at the call point) which function is to be called. That information becomes data, not code.

Share this post


Link to post
Share on other sites
Quote:
Original post by SirLuthor
Pragma Fury, I don't know what you were planning to do with your second implementation, but I do know that that mapping of strings to functions is the basis of my console at least, and if I didn't have function pointers, I'd be stuck with a lot of repetative, ugly code.


Actually, the only place I've used string->function mapping was in a quasi-sql driver I did for work. Long story short, we used it to make our own stored proc style function calls. I just adapted it to a more game-like scenerio.

Quote:
Original post by Gink
So they are used for convenience and not because they are needed?


I would somewhat agree with this. A lot of what you can do with function pointers can be done in an alternate way. Though that often results in some very nasty code and bad design practices.

Share this post


Link to post
Share on other sites
Quote:
Original post by Gink
So they are used for convenience and not because they are needed?


In the same way that C++ is used for convenience, and not because we can't do everything in assembly.

The thing is that they can accept ANY (appropriate) function, so unrelated bits of the program can interoperate better. For example, in the GLUT library they use callbacks a lot, which looks something like this:

//==VVV== Inside the GLUT Library ==VVV==
typedef void (* f_void_void )( void );

f_void_void display_function;

void glutDisplayFunc( f_void_void function ) {
display_function = function;
}

void glutMainLoop ( void ) {
while ( 1 ) {
//...
display_function();
swap_buffers();
}
}
//==^^^== Inside the GLUT Library ==^^^==
//==VVV== Inside your program ==VVV==
#include <GL/glut.h>

void render( void ) {
//...
}

int main ( void ) {
//...
glutDisplayFunc( render );
glutMainLoop();
}




In order to have glutMainLoop allways call render() without function pointers, you'd have to edit the GLUT source code (which would be a pain in the butt) and require that each program have their own version of the GLUT library instead of sharing a single one.

Hope this helps to explain :-).

Share this post


Link to post
Share on other sites
Quote:
Original post by pragma Fury
I would somewhat agree with this. A lot of what you can do with function pointers can be done in an alternate way. Though that often results in some very nasty code and bad design practices.


Loading libraries at run-time (LoadLibrary/dlopen) and calling the functions they contain (GetProcAddress/dlsym) is an example of something that is literally impossible without function pointers (or the equivalent ASM trickery), since neither the library, nor the function are available at compile, link or load time.

Share this post


Link to post
Share on other sites
Quote:
Original post by Fruny
Quote:
Original post by pragma Fury
I would somewhat agree with this. A lot of what you can do with function pointers can be done in an alternate way. Though that often results in some very nasty code and bad design practices.


Loading libraries at run-time (LoadLibrary/dlopen) and calling the functions they contain (GetProcAddress/dlsym) is an example of something that is literally impossible without function pointers (or the equivalent ASM trickery), since neither the library, nor the function are available at compile, link or load time.


True dat.
I havn't done much work with run-time libraries, so that totally skipped my mind.

Share this post


Link to post
Share on other sites
If you want to use quicksort, you have to write your own function that does the following, and if so, why?

Quote:
compare should return negative if the first argument is less than the second, zero if they are equal, and positive if the first argument is greater than the second

Share this post


Link to post
Share on other sites
The qsort function requires those return values, because that's what a quick-sort algorithm needs to function.

Here's a presentation on how a basic quicksort works.

Now, if I wanted to use qsort, and sort an array of integers in ascending order and then descending order using the same qsort algorithm, I'd write something like this:

int SortAscending(const void *element1, const void *element2)
{
int n1 = *reinterpret_cast<const int*>(element1);
int n2 = *reinterpret_cast<const int*>(element2);

if(n1 > n2)
return 1;
else if(n1 < n2)
return -1;
else
return 0;
}

int SortDescending(const void *element1, const void *element2)
{
int n1 = *reinterpret_cast<const int*>(element1);
int n2 = *reinterpret_cast<const int*>(element2);

if(n1 > n2)
return -1;
else if(n1 < n2)
return 1;
else
return 0;
}

int main(int argc, char* argv[])
{

int aValues[10];
int nIndex;
// fill our array with 10 random values.
for(nIndex=0; nIndex<10; nIndex++)
{
aValues[nIndex] = rand()%100;
}

// print the unsorted array
printf("unsorted: ");
for(nIndex=0; nIndex < 10; nIndex++)
{
printf("%2d%s",aValues[nIndex], nIndex==9?"\r\n":", ");
}

// sort ascending, passing in a pointer to my lowest->highest sorting function
qsort(aValues, 10, sizeof(int), &SortAscending);

// print the sorted array.
printf("sorted (up): ");
for(nIndex=0; nIndex < 10; nIndex++)
{
printf("%2d%s",aValues[nIndex], nIndex==9?"\r\n":", ");
}

// sort descending, passing in a pointer to my highest->lowest sorting function
qsort(aValues, 10, sizeof(int), &SortDescending);

// print the sorted array.
printf("sorted (down): ");
for(nIndex=0; nIndex < 10; nIndex++)
{
printf("%2d%s",aValues[nIndex], nIndex==9?"\r\n":", ");
}


return 0;
}




output:
unsorted:      41, 67, 34,  0, 69, 24, 78, 58, 62, 64
sorted (up): 0, 24, 34, 41, 58, 62, 64, 67, 69, 78
sorted (down): 78, 69, 67, 64, 62, 58, 41, 34, 24, 0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this