Game programming/Function pointers

< Game programming

In C, pointers are everywhere. You are probably familiar with pointers to variables. Maybe even pointers to structs. A pointer is a variable which holds a memory address. It usually has some useful value, like a acting as a reference to a variable in a different scope. In C, you can also have pointers to functions.

Requirements

Objectives

Introduction

First, let's look at a function declaration.

   double getAvg(double a, double b)
   {
       return (a + b) / 2;
   }

As you can see, we have here a function called "getAvg". It receives two doubles and returns a double.

Explanation

A pointer to a function does looks mostly not different from a regular function, except it has the '*' symbol as in all pointers, and parenthesis as follows:

   /* Declaration */
   double (*fp(double, double));
   
   /* Assignment */
   fp = &getAvg;
   
   /* Use */
   fp(2, 3);

Here we have a pointer called "fp", so we'll refer to it as such. It is a pointer to a function that receives two doubles and returns a double. Note how we do not add the parenthesis after getAvg when we assign it's address to fp. Also note the '&' operator. Using a pointer to a function is not different from using a normal function. Hence, we could do the following:

   printf("fp(2, 3) = %f.2\n", fp(2, 3));

Application

Pointers to functions serve three general purposes. One is that they provide a way to have methods in structs, the second is that they allow for some degree of polymorphism, and the third is passing functions to functions.

To create methods in a struct,

   #include <stdio.h>
   
   typedef struct
   {
       double a;
       double b;
       
       double (*getAvg)(MyStruct_t*);
   } MyStruct_t;
   
   double _MyStruct_t_getAvg(MyStruct_t* this)
   {
       return (this->a + this->b) / 2;
   }
   
   MyStruct_t* createMyStruct(double da, double db)
   {
       MyStruct_t* new = (MyStruct_t*) malloc(sizeof(MyStruct_t));
       
       new->a = da;
       new->b = db;
       new->getAvg = &_MyStruct_t_getAvg;
       
       return new;
   }
   
   int main(int argc, char* argv[])
   {
       MyStruct_t* strct = createMyStruct(2, 3);
       printf("getAvg() = %f.2", strct->getAvg(strct));
       
       return 0;
   }

Note: This example isn't that useful. It requires work.

As an example of polymorphism,

   #include <stdio.h>
   
   void doOne(void)
   {
       printf("I've done One\n");
   }
   
   void doTwo(void)
   {
       printf("I've done Two\n");
   }
   
   void doNothing(void)
   {
       printf("I've done nothing\n");
   }
   
   int main(int argc, char* argv[])
   {
       void (*work)(void) = doNothing;
       int state;
       
       for(state = 0; state < 2; ++state)
       {
           if(state == 0)
           {
               work = &doOne;
           }
           else if(state == 1)
           {
               work = &doTwo;
           }
           else
           {
               work = &doNothing;
           }
           
           printf("State %d,\n", state);
           work();
       }
       
       printf("Last work:\n");
       work();
       
       return 0;
   }

And an example of sending functions through functions,

   #include <stdio.h>
   
   void doWork(void (*beforeBegin)(void), void (*afterDone)(void))
   {
       beforeBegin();
       
       printf("I've done some work.\n");
       
       afterDone();
   }
   
   void logBegin(void)
   {
       printf("LOG: I'm about to do some work.\n");
   }
   
   void logEnd(void)
   {
       printf("LOG: I'm done doing some work.\n");
   }
   
   int main(int argc, char* argv[])
   {
       doWork(logBegin, logEnd);
       
       return 0;
   }
This article is issued from Wikiversity - version of the Thursday, July 11, 2013. The text is available under the Creative Commons Attribution/Share Alike but additional terms may apply for the media files.