Function Pointers with typedef - Method 1 ========================================= In this section, you are going to learn .. panels:: :container: container pb-4 :column: col-lg-12 p-2 :card: shadow Topics in this section, * :ref:`Section 1 : Basic function pointer ` * :ref:`Section 2 : Functions taking function pointers as an arguement ` * :ref:`Example 2.1 : Basic Example ` * :ref:`Example 2.2 : Let us look at a Real time example ` * :ref:`Example 3 : Functions returning function pointers ` * :ref:`Example 3.1 : Basic Example ` * :ref:`Example 3.2 : Let us look at a Real time sorting example ` * :ref:`Example 4 : Function taking function pointers as an arguement and returning function pointers ` * :ref:`Example 5 : Array of function pointers ` * :ref:`Syntax of Array of function pointers ` * :ref:`Example 5.1 : Array of function pointers to implement calculator ` * :ref:`Example 5.2 : Array of Function Pointers for handling asynchronous events ` * :ref:`Example 6 : Function Pointers inside structures ` * :ref:`Summary ` .. _function_ptr_fp_typedef_m1_ex_1: .. tab-set:: .. tab-item:: Section 1 : Basic function pointer .. tab-set:: .. tab-item:: Syntax of basic function pointer * Step 1 : Define function type .. code-block:: c typedef return_type function_type (parameters_list); * Step 2 : Define function Pointer using function type .. code-block:: c function_type *fp; * Step 3 : Assing address of a function to ``fp`` .. code-block:: c fp = funx; * Step 4 : Call the function using ``fp`` .. code-block:: c fp(); // This is equal to funx() * In this program, * Function sum() returns sum of two integers .. code-block:: c :linenos: :emphasize-lines: 12 #include int sum(int a, int b) { return a + b; } int main(void) { int s; s = sum(5, 6); printf("sum = %d\n", s); return 0; } * Now let us replace call to function sum() using function pointer * Step 1 : Define function type .. code-block:: c typedef int fp(int, int); * Step 2 : Define function Pointer using function type .. code-block:: c fp *calc; * Step 3 : Define a function .. code-block:: c int sum(int a, int b) { return a + b; } .. panels:: :container: container pb-4 :column: col-lg-12 p-2 :card: shadow Note that, return type and function parameters of function pointer should match with that of actual function * Step 4 : Assign function pointer with address of an actual function .. code-block:: c calc = sum; OR .. code-block:: c calc = ∑ * Step 5 : Use the function pointer to call the function .. code-block:: c s = calc(5, 6); OR .. code-block:: c s = (*calc)(5, 6); * See full program below .. code-block:: c :linenos: :emphasize-lines: 4, 7, 16, 19 #include // Step 1 : Define a function pointer typedef int fp(int, int); // Step 2 : Define function Pointer using function type fp *calc; // Step 3 : Define a function int sum(int a, int b) { return a + b; } int main(void) { int s; // Step 4 : Assign function pointer with address of an actual function calc = sum; // Step 5 : Use the function pointer to call the function s = calc(5, 6); printf("sum = %d\n", s); return 0; } .. _function_ptr_fp_typedef_m1_ex_2: .. tab-set:: .. tab-item:: Section 2 : Functions taking function pointers as an arguement * In this section, you are going to learn .. panels:: :container: container pb-4 :column: col-lg-12 p-2 :card: shadow * 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 .. _function_ptr_fp_typedef_m1_ex_3: .. tab-set:: .. tab-item:: Example 2.1 : Basic Example * Step 1 : Define a function called ``fx()`` .. code-block:: c void fx(void) { printf("Inside function fx()\n"); } * Step 2 : Identify the function pointer prototype ``fp`` for above function .. code-block:: c typedef void fp(void); fp *fptr; * Step 3 : Define a function ``fy()`` taking function pointer ``fp`` as an arguement .. code-block:: c :emphasize-lines: 1 void fy(fp *fptr) { } * Step 4 : Call the function ``fx()`` using function pointer ``fp`` inside ``fy()`` .. code-block:: c :emphasize-lines: 3 void fy(fp *fptr) { fptr(); } * Step 5 : Call the function ``fy()`` by passing ``fx`` as argument .. code-block:: c fy(fx); * See full program below .. code-block:: c :linenos: :emphasize-lines: 8, 10, 15 #include typedef void fp(void); void fx(void) { printf("Inside function fx()\n"); } void fy(fp *fptr) { fptr(); } int main(void) { fy(fx); return 0; } .. code-block:: c Inside function fx() .. _function_ptr_fp_typedef_m1_ex_4: .. tab-set:: .. tab-item:: Example 2.2 : Let us look at a Real time example * Step 1 : Define two functions ``sum()``, ``sub()`` .. code-block:: c int sum(int a, int b) { return a + b; } int sub(int a, int b) { return a - b; } .. panels:: :container: container pb-4 :column: col-lg-12 p-2 :card: shadow Note that, Prototypes of sum() and sub() are matching * Step 2 : Identify the function pointer prototype for functions ``sum()``, ``sub()`` .. code-block:: c typedef int fp(int, int); fp *calc; .. panels:: :container: container pb-4 :column: col-lg-12 p-2 :card: shadow * 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 .. code-block:: c int do_calculation(fp *calc, int a, int b) { } .. panels:: :container: container pb-4 :column: col-lg-12 p-2 :card: shadow * ``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`` .. code-block:: c int do_calculation(fp *calc, int a, int b) { return calc(a, b); } .. panels:: :container: container pb-4 :column: col-lg-12 p-2 :card: shadow * ``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 .. panels:: :container: container pb-4 :column: col-lg-12 p-2 :card: shadow * 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 .. panels:: :container: container pb-4 :column: col-lg-12 p-2 :card: shadow * 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 ! .. code-block:: c :linenos: :emphasize-lines: 13, 15, 22, 26 #include typedef int fp(int, int); int sum(int a, int b) { return a + b; } int sub(int a, int b) { return a - b; } int do_calculation(fp *calc, int a, int b) { return calc(a, b); } int main(void) { int s; s = do_calculation(sum, 5, 6); printf("sum = %d\n", s); s = do_calculation(sub, 5, 6); printf("sub = %d\n", s); return 0; } .. code-block:: c :linenos: sum = 11 sub = -1 .. _function_ptr_fp_typedef_m1_ex_5: .. tab-set:: .. tab-item:: Example 3 : Functions returning function pointers * In this section, you are going to learn .. panels:: :container: container pb-4 :column: col-lg-12 p-2 :card: shadow Functions returning function pointers .. _function_ptr_fp_typedef_m1_ex_6: .. tab-set:: .. tab-item:: Example 3.1 : Basic Example * Step 1 : Define a function ``fx`` .. code-block:: c void fx(void) { printf("Inside function fx()\n"); } * Step 2 : Identify the function pointer prototype for function ``fx`` .. code-block:: c typedef void fp(void); * Step 2 : Define a function ``get_fx_operation`` which returns function pointer .. code-block:: c fp * get_fx_operation(void) { return fx; } Note the syntax ! * Step 3 : Call ``get_fx_operation`` and store the return value in function pointer ``fx_p`` .. code-block:: c fx_p = get_fx_operation(); Where the prototype of ``fx_p`` should match with prototype of ``fx()`` .. code-block:: c fp *fx_p; * Step 4 : Call the function using ``fx_p`` .. code-block:: c fx_p(); // This calls function fx() * Step 5 : See the full program below .. code-block:: c :linenos: :emphasize-lines: 8, 15, 17, 19 #include typedef void fp(void); void fx(void) { printf("Inside function fx()\n"); } fp * get_fx_operation(void) { return fx; } int main(void) { fp *fx_p; fx_p = get_fx_operation(); fx_p(); // This calls function fx() return 0; } .. _function_ptr_fp_typedef_m1_ex_7: .. tab-set:: .. tab-item:: Example 3.2 : Let us look at a Real time sorting example In this example, program decides the sorting mechanism to be used at run time based on the array size * Step 1 : Define two sorting algorithm functions .. code-block:: c void insertion_sort(int *arr, int n) { } void selection_sort(int *arr, int n) { } * Step 2 : Define function pointer type for above functions .. code-block:: c typedef void sort_fp(int *arr, int n) * Step 3 : ``get_sort_method`` returns sorting method to be used based on array size .. code-block:: c sort_fp * get_sort_method(int n) { if (n <= 2) return insertion_sort; else return selection_sort; } * Step 4 : ``analyse_data`` calls ``get_sort_method`` function to sort .. code-block:: c void analyse_data(int *arr, int n) { sort_fp *sort_fptr; sort_fptr = get_sort_method(n); sort_fptr(arr, n); } * Step 5 : What is the advantage ? .. panels:: :container: container pb-4 :column: col-lg-12 p-2 :card: shadow * 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`` .. panels:: :container: container pb-4 :column: col-lg-12 p-2 :card: shadow * In real time, ``analyse_data`` can be very big function with calls to many function pointers * Step 4 : See the full program below .. code-block:: c :linenos: :emphasize-lines: 16, 18, 25, 27 #include typedef void sort_fp(int *arr, int n); int arr[] = { 47, 13, 63, 29, 7 }; void insertion_sort(int *arr, int n) { } void selection_sort(int *arr, int n) { } sort_fp * get_sort_method(int n) { if (n <= 2) return insertion_sort; else return selection_sort; } void analyse_data(int *arr, int n) { sort_fp *sort_fptr; sort_fptr = get_sort_method(n); sort_fptr(arr, n); } int main(void) { analyse_data(arr, sizeof(arr) / sizeof(arr[0]) ); return 0; } .. _function_ptr_fp_typedef_m1_ex_8: .. tab-set:: .. tab-item:: Example 4 : Function taking function pointers as an arguement and returning function pointers * Step 1 : Define a function pointer type ``fp`` .. code-block:: c typedef void fp_param(int); typedef void fp_return(void); * 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 Example 2 and Example 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`` .. code-block:: c fp_return * get_fx_operation( fp_param * fs_p ) { 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`` .. code-block:: c fx_p = get_fx_operation(sample_fun); * Step 3 : See the full program below .. code-block:: c :linenos: :emphasize-lines: 22, 38, 40 #include typedef void fp_param(int); typedef void fp_return(void); void fx(void) { printf("Inside function fx() : Positive\n"); } void gx(void) { printf("Inside function gx() : Negative\n"); } void sample_fun(int a) { printf("a = %d \n", a); } fp_return * get_fx_operation( fp_param * fs_p ) { int a = 5; fs_p(a); if (a > 0) return fx; else return gx; } int main(void) { fp_return *fx_p; fx_p = get_fx_operation(sample_fun); fx_p(); // This calls function fx() return 0; } .. _function_ptr_fp_typedef_m1_ex_9: .. tab-set:: .. tab-item:: Example 5 : Array of function pointers .. panels:: :container: container pb-4 :column: col-lg-12 p-2 :card: shadow * Similar functions can be grouped into an array * We call this as array of function pointers * Array of function pointers enables asynchronous event handling .. _function_ptr_fp_typedef_m1_ex_10: .. tab-set:: .. tab-item:: Syntax of Array of function pointers .. code-block:: c typedef return_type function_type (parameters_list); function_type *fp_arr[] = {functions_list}; .. _function_ptr_fp_typedef_m1_ex_11: .. tab-set:: .. tab-item:: Example 5.1 : Array of function pointers to implement calculator * 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 .. code-block:: c typedef void fp(int, int); fp *calc[] = { sum, sub, mul }; * Step 2 : Find number of elements in an array generic way .. panels:: :container: container pb-4 :column: col-lg-12 p-2 :card: shadow Number of elements in Array = Sizeof_Array / Size of One element .. panels:: :container: container pb-4 :column: col-lg-12 p-2 :card: shadow Number of elements in ``calc`` = sizeof(calc) / sizeof(calc[0]) * Step 3 : Call the functions using array of function pointers .. code-block:: c 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 .. code-block:: c :linenos: :emphasize-lines: 18, 20, 26 #include void sum(int a, int b) { printf("Function sum called : a = %d, b = %d, sum = %d\n", a, b, a + b); } void sub(int a, int b) { printf("Function sub called : a = %d, b = %d, sub = %d\n", a, b, a - b); } void mul(int a, int b) { printf("Function mul called : a = %d, b = %d, mul = %d\n", a, b, a * b); } typedef void fp(int, int); fp *calc[] = { sum, sub, mul }; int main(void) { for (int i = 0; i < sizeof(calc)/sizeof(calc[0]); i++) { calc[i](5, 6); } return 0; } * Output is as below .. panels:: :container: container pb-4 :column: col-lg-12 p-2 :card: shadow 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 .. _function_ptr_fp_typedef_m1_ex_12: .. tab-set:: .. tab-item:: Example 5.2 : Array of Function Pointers for handling asynchronous events Asynchoronous events - Can arrive at any time .. panels:: :container: container pb-4 :column: col-lg-12 p-2 :card: shadow In below example, events are generated randomly and handled dynamically * Step 1 : Define functions which handle specific events .. code-block:: c 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 .. code-block:: c typedef void fp(void); fp *ev_cb[] = { ev_connect_cb, ev_disconnect_cb, ev_reconnect_cb, }; * Step 3 : Call these functions based on event generated .. code-block:: c ev_cb[ev_id](); * Step 4 : See full program below .. code-block:: c :linenos: :emphasize-lines: 32, 33, 34, 35, 36, 37, 38, 54 #include #include #include #include void handle_event(int ev_id); enum events { EV_INIT, EV_CONNECT = EV_INIT, EV_DISCONNECT, EV_RECONNECT, EV_MAX = EV_RECONNECT }; 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"); } typedef void fp(void); fp *ev_cb[] = { ev_connect_cb, ev_disconnect_cb, ev_reconnect_cb, }; void generate_events() { int i; for (;;) { for (i = 0; i < EV_MAX; i++) { int ev_id = (rand() % (EV_MAX - EV_INIT + 1)) + EV_INIT; handle_event(ev_id); } } } void handle_event(int ev_id) { ev_cb[ev_id](); } int main(void) { generate_events(); return 0; } .. _function_ptr_fp_typedef_m1_ex_13: .. tab-set:: .. tab-item:: Example 6 : Function Pointers inside structures * 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 .. code-block:: c :emphasize-lines: 10, 11 typedef int fp(struct student_db *s); struct student_db { int id; int age; int marks; char name[32]; fp *get_age_p; fp *get_marks_p; }; .. panels:: :container: container pb-4 :column: col-lg-12 p-2 :card: shadow ``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 .. code-block:: c :emphasize-lines: 6, 7 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 .. code-block:: c s1.get_age_p(&s1); * Step 4 : See full program below .. code-block:: c :linenos: :emphasize-lines: 14, 15, 35, 36, 44, 45 #include struct student_db; typedef int fp(struct student_db *s); struct student_db { int id; int age; int marks; char name[32]; fp *get_age_p; fp *get_marks_p; }; int get_age(struct student_db *s) { return s->age; } int get_marks(struct student_db *s) { return s->marks; } int main(void) { struct student_db s1 = { .id = 101, .age = 20, .marks = 97, .name = "Adam", .get_age_p = get_age, .get_marks_p = get_marks }; struct student_db s2 = { .id = 102, .age = 21, .marks = 98, .name = "Ram", .get_age_p = get_age, .get_marks_p = get_marks }; printf("Age of s1 = %d\n", s1.get_age_p(&s1)); printf("Marks of s1 = %d\n", s1.get_marks_p(&s1)); printf("Age of s2 = %d\n", s2.get_age_p(&s2)); printf("Marks of s2 = %d\n", s2.get_marks_p(&s2)); return 0; } .. _function_ptr_fp_typedef_m1_ex_14: .. tab-set:: .. tab-item:: Summary ===================================================== ====================================================== Simple function Pointer : Method 1 ===================================================== ====================================================== typedef return_type fun (parameter_list); Basic Function Pointer syntax fun \*fp; fp = function; ``fp`` is assigned with address of ``function`` fp(); ``fp()`` is equal to ``function()`` ===================================================== ====================================================== ===================================================== ====================================================== Simple function Pointer : Method 2 ===================================================== ====================================================== typedef return_type fun (parameter_list); Basic Function Pointer syntax fun \*fp; fp = &function; `fp`` is assigned with address of ``function`` (\*fp) (); ``(*fp) ()`` is equal to ``function()`` ===================================================== ====================================================== ===================================================== ====================================================== Array of function Pointers ===================================================== ====================================================== typedef return_type fun (parameter_list); Basic Array of Function Pointers syntax fun \*fp[]; 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()`` ===================================================== ====================================================== .. card:: See Also * Current Module * :doc:`function_ptr` * Previous Module * :doc:`../ptr_to_array/ptr_to_array` * Next Module * :doc:`../pre_incr_ptr/pre_incr_ptr` * Other Modules * :doc:`../variable_and_ptr/variable_and_ptr` * :doc:`../array_n_ptrs/array_n_ptrs` * :doc:`../malloc_ptr/malloc_ptr` * :doc:`../typecasting_n_ptr/typecasting_n_ptr` * :doc:`../funcs_n_ptrs/funcs_n_ptrs` * :doc:`../memcpy_ptr/memcpy_ptr` * :doc:`../const_ptr/const_ptr` * :doc:`../void_ptr/void_ptr` * :doc:`../array_of_ptr/array_of_ptr` * :doc:`../post_incr_ptr/post_incr_ptr` * :doc:`../pre_decr_ptr/pre_decr_ptr` * :doc:`../post_decr_ptr/post_decr_ptr`