Function Pointers without typedef

In this chapter, you are going to learn

Uses of funcion pointers ?

return_type (*function_pointer)(parameters_list);

  • In this program,

    • Function sum() returns sum of two integers

 1#include <stdio.h>
 2
 3int sum(int a, int b)
 4{
 5        return a + b;
 6}
 7
 8int main(void)
 9{
10        int s;
11
12        s = sum(5, 6);
13
14        printf("sum = %d\n", s);
15
16        return 0;
17}
  • Now let us replace call to function sum() using function pointer

    • Step 1 : Define a function pointer

    int (*calc)(int, int);
    
    • Step 2 : Define a function

    int sum(int a, int b)
    {
            return a + b;
    }
    

    Note that, return type and function parameters of function pointer should match with that of actual function

    • Step 3 : Assign function pointer with address of an actual function

    calc = sum;
    

    OR

    calc = &sum;
    
    • Step 4 : Use the function pointer to call the function

    s = calc(5, 6);
    

    OR

    s = (*calc)(5, 6);
    
  • See full program below

 1#include <stdio.h>
 2
 3// Step 1 : Define a function pointer
 4int (*calc)(int, int);
 5
 6// Step 2 : Define a function
 7int sum(int a, int b)
 8{
 9        return a + b;
10}
11
12int main(void)
13{
14        int s;
15
16        // Step 3 : Assign function pointer with address of an actual function
17        calc = sum;
18
19        // Step 4 : Use the function pointer to call the function
20        s = calc(5, 6);
21
22        printf("sum = %d\n", s);
23
24        return 0;
25}
  • In this section, you are going to learn

  • Functions taking function pointers as an arguement

  • Step 1 : Define a function called fx()

  • Step 2 : Identify the function pointer prototype fp for above function

  • Step 3 : Define a function fy() taking function pointer fp as an arguement

  • Step 4 : Call the function fx() using function pointer fp inside fy()

  • Step 5 : Call the function fy() by passing fx as argument

  • Step 6 : Let us see few examples

  • Step 1 : Define a function called fx()

void fx(void)
{
        printf("Inside function fx()\n");
}
  • Step 2 : Identify the function pointer prototype fp for above function

void (*fp)(void)
  • Step 3 : Define a function fy() taking function pointer fp as an arguement

void fy(void (*fp)(void))
{
}
  • Step 4 : Call the function fx() using function pointer fp inside fy()

void fy(void (*fp)(void))
{
        fp();
}
  • Step 5 : Call the function fy() by passing fx as argument

fy(fx);
  • See full program below

 1#include <stdio.h>
 2
 3void fx(void)
 4{
 5        printf("Inside function fx()\n");
 6}
 7
 8void fy(void (*fp)(void))
 9{
10        fp();
11}
12
13int main(void)
14{
15        fy(fx);
16
17        return 0;
18}
Inside function fx()
  • Step 1 : Define two functions sum(), sub()

int sum(int a, int b)
{
        return a + b;
}

int sub(int a, int b)
{
        return a - b;
}

Note that, Prototypes of sum() and sub() are matching

  • Step 2 : Identify the function pointer prototype for functions sum(), sub()

int (*calc)(int, int)
  • In this example, calc is the function pointer

  • return type of calc is int. Because return type of sum and sub is int

  • Number of parameters of calc is two. Because Number of parameters of sum and sub is two

  • Type of first parameter is int. Because type of first parameter is int in sum and sub

  • Type of second parameter is int. Because type of second parameter is int in sum and sub

  • Step 3 : Define a function do_calculation() taking function pointer calc as an arguement

int do_calculation(int (*calc)(int, int), int a, int b)
{
}
  • do_calculation takes 3 arguements

  • First is function pointer calc

  • Second is integer a

  • Third is integer b

  • Step 4 : Call the function pointer calc inside do_calculation

int do_calculation(int (*calc)(int, int), int a, int b)
{
        return calc(a, b);
}
  • calc is a function pointer which can hold the address of any function whose prototype matches with that of calc

  • Step 5 : Call the function do_calculation() by passing sum or sub as argument

  • While calling do_calculation(), pass 3 arguements

  • First : Address of a function whose prototype matches with that of calc

  • Second : integer

  • Third : integer

  • See full program below

  • Function do_calculation is called first time to perform addition using sum

  • Function do_calculation is called second time to perform subtraction using sub

  • In both cases, definition of function do_calculation is common !

 1#include <stdio.h>
 2
 3int sum(int a, int b)
 4{
 5        return a + b;
 6}
 7
 8int sub(int a, int b)
 9{
10        return a - b;
11}
12
13int do_calculation(int (*calc)(int, int), int a, int b)
14{
15        return calc(a, b);
16}
17
18int main(void)
19{
20        int s;
21
22        s = do_calculation(sum, 5, 6);
23
24        printf("sum = %d\n", s);
25
26        s = do_calculation(sub, 5, 6);
27
28        printf("sub = %d\n", s);
29
30        return 0;
31}
1sum = 11
2sub = -1
  • In this section, you are going to learn

Functions returning function pointers

  • Step 1 : Define a function fx

    void fx(void)
    {
            printf("Inside function fx()\n");
    }
    
  • Step 2 : Define a function get_fx_operation which returns function pointer

    void (* get_fx_operation(void) ) (void)
    {
            return fx;
    }
    

    Note the syntax !

    • Step 2.1 : Write the prototype of function pointer

    void (*) (void)
    {
    }
    
    • Step 2.2 : Write the function name and its arguements

    void (* get_fx_operation(void) ) (void)
    {
    }
    
    • Step 2.3 : Return the address of a function

    void (* get_fx_operation(void) ) (void)
    {
            return fx;
    }
    
  • Step 3 : Call get_fx_operation and store the return value in function pointer fx_p

    fx_p = get_fx_operation();
    

    Where the prototype of fx_p should match with prototype of fx()

    void (*fx_p)(void);
    
  • Step 4 : Call the function using fx_p

    fx_p(); // This calls function fx()
    
  • Step 5 : See the full program below

 1#include <stdio.h>
 2
 3void fx(void)
 4{
 5        printf("Inside function fx()\n");
 6}
 7
 8void (* get_fx_operation(void) ) (void)
 9{
10        return fx;
11}
12
13int main(void)
14{
15        void (*fx_p)(void);
16
17        fx_p = get_fx_operation();
18
19        fx_p();  // This calls function fx()
20
21        return 0;
22}

In this example, program decides the sorting mechanism to be used at run time based on the array size

  • Step 1 : get_sort_method returns sorting method to be used based on array size

void ( *get_sort_method(int n) ) (int *, int n)
{
        if (n <= 2)
                return insertion_sort;
        else
                return selection_sort;
}
  • Step 2 : analyse_data calls get_sort_method function to sort

void analyse_data(int *arr, int n)
{
        void (*sort_fp)(int *arr, int n);

        sort_fp = get_sort_method(n);

        sort_fp(arr, n);
}
  • Step 3 : What is the advantage ?

  • Whenever the array size changes the function analyse_data need not change !

  • If analyse_data is defined in a seprate x.c file, we need not recompile x.c

  • In real time, analyse_data can be very big function with calls to many function pointers

  • Step 4 : See the full program below

 1#include <stdio.h>
 2
 3int arr[] = { 47, 13, 63, 29, 7 };
 4
 5void insertion_sort(int *arr, int n)
 6{
 7}
 8
 9void selection_sort(int *arr, int n)
10{
11}
12
13void ( *get_sort_method(int n) ) (int *, int n)
14{
15        if (n <= 2)
16                return insertion_sort;
17        else
18                return selection_sort;
19}
20
21void analyse_data(int *arr, int n)
22{
23        void (*sort_fp)(int *arr, int n);
24
25        sort_fp = get_sort_method(n);
26
27        sort_fp(arr, n);
28}
29
30int main(void)
31{
32        analyse_data(arr, sizeof(arr) / sizeof(arr[0]) );
33
34        return 0;
35}

Can you guess what is happening in below program ?

 1#include <stdio.h>
 2
 3int fa(void)
 4{
 5        printf("Inside function fa\n");
 6        return 0;
 7}
 8
 9int (* funx(void) ) (void)
10{
11        return fa;
12}
13
14int (*(* funy(void)) (void)) (void)
15{
16        return funx;
17}
18
19int (*(*(* funz(void)) (void)) (void)) (void)
20{
21        return funy;
22}
23
24int main(void)
25{
26        funz()()()();
27        return 0;
28}
  • Step 1 : Define a function get_fx_operation which takes function pointer as arguement and returns a function pointer

    • get_fx_operation is written using concepts from Section 2 and Section 3

    • get_fx_operation takes fs_p as arguement which is a function pointer which can hold the address of a function which returns void and takes int as an arguement

    • get_fx_operation returns fx or gx depending on the value of a

void (* get_fx_operation( void (*fs_p)(int) ) ) (void)
{
        int a = 5;

        fs_p(a);

        if (a > 0)
                return fx;
        else
                return gx;
}
  • Step 2 : Call get_fx_operation and pass address of a function

    • We are passing address of sample_fun as arguement to get_fx_operation

fx_p = get_fx_operation(sample_fun);
  • Step 3 : See the full program below

 1#include <stdio.h>
 2
 3void fx(void)
 4{
 5        printf("Inside function fx() : Positive\n");
 6}
 7
 8void gx(void)
 9{
10        printf("Inside function gx() : Negative\n");
11}
12
13void sample_fun(int a)
14{
15        printf("a = %d \n", a);
16}
17
18void (* get_fx_operation( void (*fs_p)(int) ) ) (void)
19{
20        int a = 5;
21
22        fs_p(a);
23
24        if (a > 0)
25                return fx;
26        else
27                return gx;
28}
29
30int main(void)
31{
32        void (*fx_p)(void);
33
34        fx_p = get_fx_operation(sample_fun);
35
36        fx_p();  // This calls function fx()
37
38        return 0;
39}
  • Similar functions can be grouped into an array

  • We call this as array of function pointers

  • Array of function pointers enables asynchronous event handling

return_type ( *fp_array [ ] ) ( parameter_list ) = { functions_list };

  • Step 1 : Define an array of function pointers

    • calc is an array of function pointers

    • Each element in this array is a function which takes two integers as argement and returns void

void ( *calc [ ] )( int, int ) = { sum, sub, mul };

  • Step 2 : Find number of elements in an array generic way

Number of elements in Array = Sizeof_Array / Size of One element

Number of elements in calc = sizeof(calc) / sizeof(calc[0])

  • Step 3 : Call the functions using array of function pointers

 calc[i](5, 6);

// calc[0](5, 6) equals sum(5, 6)
// calc[1](5, 6) equals sub(5, 6)
// calc[2](5, 6) equals mul(5, 6)
  • Step 4 : See full program below

 1#include <stdio.h>
 2
 3void sum(int a, int b)
 4{
 5        printf("Function sum called : a = %d, b = %d, sum = %d\n", a, b, a + b);
 6}
 7
 8void sub(int a, int b)
 9{
10        printf("Function sub called : a = %d, b = %d, sub = %d\n", a, b, a - b);
11}
12
13void mul(int a, int b)
14{
15        printf("Function mul called : a = %d, b = %d, mul = %d\n", a, b, a * b);
16}
17
18void (*calc[])(int, int) = { sum, sub, mul};
19
20int main(void)
21{
22        printf("size of array = %ld\n", sizeof(calc));
23        printf("size of one element = %ld\n", sizeof(calc[0]));
24        printf("Number of elements in array = %ld\n", sizeof(calc)/sizeof(calc[0]));
25
26        for (int i = 0; i < sizeof(calc)/sizeof(calc[0]); i++)
27        {
28                calc[i](5, 6);
29        }
30
31        return 0;
32}
  • Output is as below

size of array = 24

size of one element = 8

Number of elements in array = 3

Function sum called : a = 5, b = 6, sum = 11

Function sub called : a = 5, b = 6, sub = -1

Function mul called : a = 5, b = 6, mul = 30

Asynchoronous events - Can arrive at any time

In below example, events are generated randomly and handled dynamically

  • Step 1 : Define functions which handle specific events

void ev_connect_cb(void)
{
        printf("Handled ev_connect_cb\n");
}

void ev_disconnect_cb(void)
{
        printf("Handled ev_disconnect_cb\n");
}

void ev_reconnect_cb(void)
{
        printf("Handled ev_reconnect_cb\n");
}
  • Step 2 : Map these functions to array of function pointers

void (*ev_cb[]) (void) = {
        ev_connect_cb,
        ev_disconnect_cb,
        ev_reconnect_cb,
        };
  • Step 3 : Call these functions based on event generated

ev_cb[ev_id]();
  • Step 4 : See full program below

 1#include <stdio.h>
 2#include <stdlib.h>
 3#include <time.h>
 4#include <unistd.h>
 5
 6void handle_event(int ev_id);
 7
 8enum events
 9{
10        EV_INIT,
11        EV_CONNECT = EV_INIT,
12        EV_DISCONNECT,
13        EV_RECONNECT,
14        EV_MAX = EV_RECONNECT
15};
16
17void ev_connect_cb(void)
18{
19        printf("Handled ev_connect_cb\n");
20}
21
22void ev_disconnect_cb(void)
23{
24        printf("Handled ev_disconnect_cb\n");
25}
26
27void ev_reconnect_cb(void)
28{
29        printf("Handled ev_reconnect_cb\n");
30}
31
32void (*ev_cb[]) (void) = {
33                        ev_connect_cb,
34                        ev_disconnect_cb,
35                        ev_reconnect_cb,
36                        };
37
38void generate_events()
39{
40        int i;
41        for (;;) {
42                for (i = 0; i < EV_MAX; i++) {
43                        int ev_id = (rand() %
44                        (EV_MAX - EV_INIT + 1)) + EV_INIT;
45                        handle_event(ev_id);
46                }
47        }
48}
49
50void handle_event(int ev_id)
51{
52        ev_cb[ev_id]();
53}
54
55int main(void)
56{
57        generate_events();
58        return 0;
59}
  • C language allows programmer to define function pointers inside a structure

  • After all, function pointer is another variable

  • Step 1 : Declare function pointers inside a structure

struct student_db
{
        int id;
        int age;
        int marks;
        char name[32];

        int (*get_age_p)  (struct student_db *s);
        int (*get_marks_p)(struct student_db *s);
};

get_age_p is a function pointer

get_marks_p is a function pointer

  • Step 2 : Assign function pointers with actual function definitions at the time of structure object creation

struct student_db s1 = {
.id = 101,
.age = 20,
.marks = 97,
.name = "Adam",
.get_age_p = get_age,
.get_marks_p = get_marks
};
  • Step 3 : Call the function via function pointers using structure object

s1.get_age_p(&s1);
  • Step 4 : See full program below

 1#include <stdio.h>
 2
 3struct student_db
 4{
 5        int id;
 6        int age;
 7        int marks;
 8        char name[32];
 9
10        int (*get_age_p)  (struct student_db *s);
11        int (*get_marks_p)(struct student_db *s);
12};
13
14int get_age(struct student_db *s)
15{
16        return s->age;
17}
18
19int get_marks(struct student_db *s)
20{
21        return s->marks;
22}
23
24int main(void)
25{
26        struct student_db s1 = {
27        .id = 101,
28        .age = 20,
29        .marks = 97,
30        .name = "Adam",
31        .get_age_p = get_age,
32        .get_marks_p = get_marks
33        };
34
35        struct student_db s2 = {
36        .id = 102,
37        .age = 21,
38        .marks = 98,
39        .name = "Ram",
40        .get_age_p = get_age,
41        .get_marks_p = get_marks
42        };
43
44        printf("Age of s1 = %d\n", s1.get_age_p(&s1));
45        printf("Marks of s1 = %d\n", s1.get_marks_p(&s1));
46
47        printf("Age of s2 = %d\n", s2.get_age_p(&s2));
48        printf("Marks of s2 = %d\n", s2.get_marks_p(&s2));
49
50        return 0;
51}

Simple function Pointer : Method 1

return_type (*fp) (parameter_list);

Basic Function Pointer syntax

fp = function;

fp is assigned with address of function

fp();

fp() is equal to function()

Simple function Pointer : Method 2

return_type (*fp) (parameter_list);

Basic Function Pointer syntax

fp = &function;

fp` is assigned with address of function

(*fp) ();

(*fp) () is equal to function()

Array of function Pointers

return_type (*fp [ ] ) (parameter_list);

Basic Array of Function Pointers syntax

fp[0] = funx, fp[1] = funy

function pointers fp[0] and fp[1] are initialised

fp[0]()

fp[0]() is equal to funx()

fp[1]()

fp[1]() is equal to funy()