Function Pointers without typedef =================================== In this chapter, you are going to learn .. panels:: :container: container pb-4 :column: col-lg-12 p-2 :card: shadow Uses of funcion pointers ? .. 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:`Section 2.1 : Basic Example ` * :ref:`Section 2.2 : Let us look at a Real time example ` * :ref:`Section 3 : Functions returning function pointers ` * :ref:`Section 3.1 : Basic Example ` * :ref:`Section 3.2 : Let us look at a Real time sorting example ` * :ref:`Section 3.3 : Function returns a function which returns a function which returns a function pointer ` * :ref:`Section 4 : Function taking function pointers as an arguement and returning function pointers ` * :ref:`Section 5 : Array of function pointers ` * :ref:`Syntax of Array of function pointers ` * :ref:`Section 5.1 : Array of function pointers to implement calculator ` * :ref:`Section 5.2 : Array of Function Pointers for handling asynchronous events ` * :ref:`Section 6 : Function Pointers inside structures ` * :ref:`Summary ` .. _function_ptr_fp_no_typedef_ex_1: .. tab-set:: .. tab-item:: Section 1 : Basic function pointer .. tab-set:: .. tab-item:: Syntax of basic function pointer .. panels:: :container: container pb-4 :column: col-lg-12 p-2 :card: shadow return_type (\*function_pointer)(parameters_list); * 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 a function pointer .. code-block:: c int (*calc)(int, int); * Step 2 : 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 3 : Assign function pointer with address of an actual function .. code-block:: c calc = sum; OR .. code-block:: c calc = ∑ * Step 4 : 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 int (*calc)(int, int); // Step 2 : Define a function int sum(int a, int b) { return a + b; } int main(void) { int s; // Step 3 : Assign function pointer with address of an actual function calc = sum; // Step 4 : Use the function pointer to call the function s = calc(5, 6); printf("sum = %d\n", s); return 0; } .. _function_ptr_fp_no_typedef_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_no_typedef_ex_3: .. tab-set:: .. tab-item:: Section 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 void (*fp)(void) * Step 3 : Define a function ``fy()`` taking function pointer ``fp`` as an arguement .. code-block:: c :emphasize-lines: 1 void fy(void (*fp)(void)) { } * Step 4 : Call the function ``fx()`` using function pointer ``fp`` inside ``fy()`` .. code-block:: c :emphasize-lines: 3 void fy(void (*fp)(void)) { fp(); } * 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 void fx(void) { printf("Inside function fx()\n"); } void fy(void (*fp)(void)) { fp(); } int main(void) { fy(fx); return 0; } .. code-block:: c Inside function fx() .. _function_ptr_fp_no_typedef_ex_4: .. tab-set:: .. tab-item:: Section 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 int (*calc)(int, int) .. 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(int (*calc)(int, int), 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(int (*calc)(int, int), 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 int sum(int a, int b) { return a + b; } int sub(int a, int b) { return a - b; } int do_calculation(int (*calc)(int, int), 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_no_typedef_ex_5: .. tab-set:: .. tab-item:: Section 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_no_typedef_ex_6: .. tab-set:: .. tab-item:: Section 3.1 : Basic Example * Step 1 : Define a function ``fx`` .. code-block:: c void fx(void) { printf("Inside function fx()\n"); } * Step 2 : Define a function ``get_fx_operation`` which returns function pointer .. code-block:: c void (* get_fx_operation(void) ) (void) { return fx; } Note the syntax ! * Step 2.1 : Write the prototype of function pointer .. code-block:: c void (*) (void) { } * Step 2.2 : Write the function name and its arguements .. code-block:: c void (* get_fx_operation(void) ) (void) { } * Step 2.3 : Return the address of a function .. code-block:: c void (* get_fx_operation(void) ) (void) { return fx; } * 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 void (*fx_p)(void); * 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 void fx(void) { printf("Inside function fx()\n"); } void (* get_fx_operation(void) ) (void) { return fx; } int main(void) { void (*fx_p)(void); fx_p = get_fx_operation(); fx_p(); // This calls function fx() return 0; } .. _function_ptr_fp_no_typedef_ex_7: .. tab-set:: .. tab-item:: Section 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 : ``get_sort_method`` returns sorting method to be used based on array size .. code-block:: c 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 .. code-block:: c 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 ? .. 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 int arr[] = { 47, 13, 63, 29, 7 }; void insertion_sort(int *arr, int n) { } void selection_sort(int *arr, int n) { } void ( *get_sort_method(int n) ) (int *, int n) { if (n <= 2) return insertion_sort; else return selection_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); } int main(void) { analyse_data(arr, sizeof(arr) / sizeof(arr[0]) ); return 0; } .. _function_ptr_fp_no_typedef_ex_8: .. tab-set:: .. tab-item:: Section 3.3 : Function returns a function which returns a function which returns a function pointer .. panels:: :container: container pb-4 :column: col-lg-12 p-2 :card: shadow Can you guess what is happening in below program ? .. code-block:: c :linenos: #include int fa(void) { printf("Inside function fa\n"); return 0; } int (* funx(void) ) (void) { return fa; } int (*(* funy(void)) (void)) (void) { return funx; } int (*(*(* funz(void)) (void)) (void)) (void) { return funy; } int main(void) { funz()()()(); return 0; } .. _function_ptr_fp_no_typedef_ex_9: .. tab-set:: .. tab-item:: Section 4 : Function taking function pointers as an arguement and returning function pointers * 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`` .. code-block:: c 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`` .. code-block:: c fx_p = get_fx_operation(sample_fun); * Step 3 : See the full program below .. code-block:: c :linenos: :emphasize-lines: 18, 34 #include 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); } void (* get_fx_operation( void (*fs_p)(int) ) ) (void) { int a = 5; fs_p(a); if (a > 0) return fx; else return gx; } int main(void) { void (*fx_p)(void); fx_p = get_fx_operation(sample_fun); fx_p(); // This calls function fx() return 0; } .. _function_ptr_fp_no_typedef_ex_10: .. tab-set:: .. tab-item:: Section 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_no_typedef_ex_11: .. tab-set:: .. tab-item:: Syntax of Array of function pointers .. panels:: :container: container pb-4 :column: col-lg-12 p-2 :card: shadow return_type ( \*fp_array [ ] ) ( parameter_list ) = { functions_list }; .. _function_ptr_fp_no_typedef_ex_12: .. tab-set:: .. tab-item:: Section 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 .. panels:: :container: container pb-4 :column: col-lg-12 p-2 :card: shadow void ( \*calc [ ] )( int, int ) = { 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, 28 #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); } void (*calc[])(int, int) = { sum, sub, mul}; int main(void) { printf("size of array = %ld\n", sizeof(calc)); printf("size of one element = %ld\n", sizeof(calc[0])); printf("Number of elements in array = %ld\n", sizeof(calc)/sizeof(calc[0])); 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 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 .. _function_ptr_fp_no_typedef_ex_13: .. tab-set:: .. tab-item:: Section 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 void (*ev_cb[]) (void) = { 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, 52 #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"); } void (*ev_cb[]) (void) = { 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_no_typedef_ex_14: .. tab-set:: .. tab-item:: Section 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: 8, 9 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); }; .. 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: 10, 11, 31, 32, 44, 45 #include 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); }; 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_no_typedef_ex_15: .. tab-set:: .. tab-item:: Summary ===================================================== ====================================================== 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()`` ===================================================== ====================================================== .. 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`