-1

So, I was looking over function pointers, and in the examples I have seen, particularly in this answer here. They seem rather redundant.

For example, if I have this code:

int addInt(int n, int m) {
    return n+m;
}
int (*functionPtr)(int,int);
functionPtr = &addInt;
int sum = (*functionPtr)(2, 3); // sum == 5

It seems here that the creating of the function pointer has no purpose, wouldn't it be easier just to do this?

int sum = addInt(2, 3); // sum == 5

If so, then why would you need to use them, so what purpose would they serve? (and why would you need to pass function pointers to other functions)

Community
  • 1
  • 1
Rivasa
  • 6,510
  • 3
  • 35
  • 64
  • 1
    Sounds like you answered part of the question yourself, passing function pointers to other functions – aaronman Oct 07 '13 at 01:03
  • Search for "higher order functions" or "first-class functions". – David Conrad Oct 07 '13 at 01:16
  • 1
    As others are pointing out, they are quite useful. I personally don't use them for function overloading, which is tacky in C at best IMHO, but they are indispensable in the case of a comparison function such as one you could pass to `qsort`, along with their required existence to specify signal handlers for specific signals. –  Oct 07 '13 at 01:22

6 Answers6

3

Simple examples of pointers seem similarly useless. It's when you start doing more complicated things that it helps. For example:

// Elsewhere in the code, there's a sum_without_safety function that blindly
// adds the two numbers, and a sum_with_safety function that validates the 
// numbers before adding them.

int (*sum_function)(int, int);
if(needs_safety) {
    sum_function = sum_with_safety;
}
else {
    sum_function = sum_without_safety;
}
int sum = sum_function(2, 3);

Or:

// This is an array of functions. We'll choose which one to call based on 
// the value of index.
int (*sum_functions)(int, int)[] = { ...a bunch of different sum functions... };
int (*sum_function)(int, int) = sum_functions[index];
int sum = sum_function(2, 3);

Or:

// This is a poor man's object system. Each number struct carries a table of 
// function pointers for various operations; you can look up the appropriate 
// function and call it, allowing you to sum a number without worrying about
// exactly how that number is stored in memory.

struct number {
    struct {
        int (*sum)(struct number *, int);
        int (*product)(struct number *, int);
        ...
    } * methods;
    void * data;
};

struct number * num = get_number();
int sum = num->methods->sum(number, 3);

The last example is basically how C++ does virtual member functions. Replace the methods struct with a hash table and you have Objective-C's method dispatch. Like variable pointers, function pointers let you abstract things in valuable ways that can make code much more compact and flexible. That power, though, isn't really apparent from the simplest examples.

Becca Royal-Gordon
  • 17,541
  • 7
  • 56
  • 91
  • Could you possibly explain a bit more what's happening with the code? I'm slightly confused. – Rivasa Oct 07 '13 at 01:13
  • It's probably a bit unclear because `*` and `&` are optional with function pointers. If you write `sum_with_safety` without parentheses, that's not a call, it's a get-address-of operation. Similarly, you can call a function pointer just by putting parentheses on the end—no need to dereference first. – Becca Royal-Gordon Oct 07 '13 at 01:15
  • Okay then, that makes more sense, but one last thing about the first example, why/what is it doing for sum function = sum with or without safety? – Rivasa Oct 07 '13 at 01:19
  • Imagine that, for example, you're summing an American football or rugby score. Some scores are valid; others are not. You write a fast `sum_without_safety` that just blindly adds the numbers, and a slow `sum_with_safety` that checks that the numbers are valid. Then there's a command line switch to choose whether you want the safety checks or not. (You could just do `if(needs_safety) { sum = sum_with_safety(2, 3); } else { sum = sum_without_safety(2, 3); }`, but if you're summing many times, it might be cleaner to check `needs_safety` once and set a function pointer.) – Becca Royal-Gordon Oct 07 '13 at 01:26
  • Okay then, but I think I'm perhaps a bit unclear about function pointers then. You have the declaration as follows: `int (*sum_function)(int, int);` but then shouldn't it be called sum function instead of sum with or without safety? – Rivasa Oct 07 '13 at 01:29
  • Or is it that the pointer of the sum_function is set to the appropriate function when you check it needs safety? – Rivasa Oct 07 '13 at 01:30
  • Elsewhere in the program, there would be two functions: `int sum_with_safety(int a, int b) { ... }` and `int sum_without_safety(int a, int b) { ... }`. The code sets `sum_function` to one of those two functions, depending on the value of `needs_safety`. – Becca Royal-Gordon Oct 07 '13 at 01:31
  • Brent, okay then! That makes so much more sense! Thank you! – Rivasa Oct 07 '13 at 01:31
2

They are one of those most useful things in C! They allow you to make a lot more modular software.

Callbacks

eg,

typedef void (*serial_data_callback)(int length, unsigned char* data);


void serial_port_data_received(serial_data_callback callback)
{
   on_data_received = callback;
}

void data_received(int length, unsigned char* data)
{
   if(on_data_received != NULL) on_data_received(length, data);
}

this means in your code you can use the general serial routines.....then you might have two things that use serial, modbus and terminal

serial_port_data_received(modbus_handle_data);
serial_port_data_received(terminal_handle_data);

and they can implement the callback function and do what's appropriate.

They allow for Object Oriented C code. It's a simple way to create "Interfaces" and then each concrete type might implement things different. For this, generally you will have a struct that will have function pointers, then functions to implement each function pointer, and a creation function that will setup the function pointers with the right functions.

   typedef struct
    {
       void (*send)(int length, unsigned char* data);
    } connection_t;

    void connection_send(connection_t* self, int length, unsigned char* data)
    {
       if(self->send != NULL) self->send(length, data);
    }

    void serial_send(int length, unsigned char* data)
    {
     // send
    }

    void tcp_send(int length, unsgined char* data)
    {
    // send
    }


void create_serial_connection(connection_t* connection)
{
   connection->send = serial_send;
}

then other code can use use a connection_t without caring whether its via serial, tcp, or anything else that you can come up with.

Keith Nicholas
  • 43,549
  • 15
  • 93
  • 156
1

What if you're writing a library in which the user inputs a function? Like qsort that can work on any type, but the user must write and supply a compare function.

Its signature is

void qsort (void* base, size_t num, size_t size,
        int (*compar)(const void*,const void*));
djechlin
  • 59,258
  • 35
  • 162
  • 290
  • So, by writing the comparison function, and passing it to qsort, the user can decide what type of element is being sorted? But then why does the function pointer have type of int? – Rivasa Oct 07 '13 at 01:07
  • @Link, the function return type is an `int` to signifiy the relation between objects. By convention zero means equality, a positive integer means the second object is "bigger" than the first, and so on. – StoryTeller - Unslander Monica Oct 07 '13 at 01:10
  • @StoryTeller, okay then, but that doesn't necessarily mean the passed function has to be an int? – Rivasa Oct 07 '13 at 01:12
  • @Link, the passed function must _return_ an `int`. It's free the reinterpret the void poiners any way it likes in order to return said int. – StoryTeller - Unslander Monica Oct 07 '13 at 01:14
1

They reduce dependencies between modules. Somtimes a library must query the calling code for things (are these objects equal? Are they in a certain order?). But you can't hardcode a call to the proper function without making the library (a) depend on the calling code and (b) non-generic.

Function pointers provide the missing pieces of information all the while keeping the library module independant of any code that might use it.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
1

They're indispensable when an API needs a callback back to the application.

user207421
  • 305,947
  • 44
  • 307
  • 483
1

Another use is for the implementation of event-emitters or signal handlers: callback functions.

Kninnug
  • 7,992
  • 1
  • 30
  • 42