Think of a callback as the poor man's polymorphism. By forcing some code, say from a library, to use a well defined and portable interface, clients can supply the interface and change the behavior of the library without touching the library code. A good example is a sorting function. If you want to let the function sort different types, you can use a callback for comparing them:
void sort ( void *list, int size,
int (*compare) ( const void *a, const void *b ) ); Then the client code only needs to supply a suitable comparison function to use the sort for multiple types:
int a[];
double b[];
char *c[];
...
sort ( a, N, cmp_int );
sort ( b, N, cmp_dbl );
sort ( c, N, cmp_str ); Another example is changing the behavior of the function entirely. Consider a binary search tree traversal:
void traverse ( struct jsw_node *root,
void (*action) ( struct jsw_node *node ) )
{
if ( root == NULL )
return;
jsw_inorder_r ( root->link[0], action );
jsw_inorder_r ( root->link[1], action );
action ( root );
} If action prints the contents of the node then you have a postorder print. If action destroys a node then you have a convenient function to destroy the entire tree. These are two wildly different operations, but because the only difference in the implementation is what you do with each node, a callback can be used with a general traverse function for both of them.